<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ja">
  <title>logbook://zem</title>
  <subtitle>Navigating the depths of technology</subtitle>
  <link href="https://zem.jp/feed/feed.xml" rel="self" />
  <link href="https://zem.jp/" />
  <updated>2026-03-08T11:14:00Z</updated>
  <id>https://zem.jp/</id>
  <author>
    <name>Masahito Zembutsu @zembutsu</name>
  </author>
  <entry>
    <title>Claude Code を LiteLLM 経由し、さくらの AI Engine へ接続する検証手順</title>
    <link href="https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html" />
    <updated>2026-03-08T11:14:00Z</updated>
    <id>https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html</id>
    <content type="html">&lt;h2 id=&quot;&quot;&gt;概要&lt;/h2&gt;
&lt;p&gt;さくらの AI Engine で Claude Code を動かすための手順です。あらかじめ、&lt;a href=&quot;https://github.com/BerriAI/litellm&quot;&gt;LiteLLM&lt;/a&gt; の接続先をさくらの AI Engine とした設定ファイルも準備し、LiteLLM の Docker コンテナを起動。それから、Claude Code が実行時に参照する環境変数 &lt;code&gt;ANTHROPIC_BASE_URL&lt;/code&gt; 等を LiteLLM に変更し、Claude Code での操作を確認します。ただし、LLM の問い合わせ先を切り替えるたあとは、Claude Code の検索機能など、Claude に依存する機能は使えなくなります&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;。&lt;/p&gt;
&lt;h2 id=&quot;-2&quot;&gt;背景&lt;/h2&gt;
&lt;p&gt;Claude Code を使いたいものの、「さくらの AI Engine上に問い合わせができないか？」という漠然とした気持ちからの調査を開始でした。既に OpenCode でさくらの AI Engine に接続できるのは確認済みでしたが、同じように Claude Code でも使えるのではという思いはありました。&lt;/p&gt;
&lt;p&gt;そして、Claude Code の公式ドキュメント&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt; を読んでいると、「LLM gateway設定」&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;ページの存在に気づきました。LiteLLM には OpenAI 互換エンドポイント&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn4&quot; id=&quot;fnref4&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt; があるため、LiteLLM を通し、さくらの AI Engine に接続できる可能性を考えました。&lt;/p&gt;
&lt;p&gt;さくらの AI Engine と Claude Code を接続する方法としては、先行事例としてダーシノさんによる「&lt;a href=&quot;https://knowledge.sakura.ad.jp/49797/&quot;&gt;さくらのAI Engine × Claude CodeではじめるAgentic Coding&lt;/a&gt;」記事があります。この記事では &lt;a href=&quot;https://musistudio.github.io/claude-code-router/&quot;&gt;Claude Code Router&lt;/a&gt;　&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn5&quot; id=&quot;fnref5&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt; を使っていましたので、別の方法で接続できないか試したいため、検証を進めました。&lt;/p&gt;
&lt;h2 id=&quot;-3&quot;&gt;前提&lt;/h2&gt;
&lt;p&gt;検証は macOS 上で行いましたが、おそらく Linux でも動作するものと思います。
LiteLLM は Docker コンテナとして動かすため、あらかじめ Docker Desktop のインストールが必要です（Linux 環境上であれば Docker Engine が入っていれば動作すると思います）。&lt;/p&gt;
&lt;h2 id=&quot;-4&quot;&gt;手順&lt;/h2&gt;
&lt;p&gt;設定ファイルをいくつか準備する必要があるため、まず &lt;code&gt;litellm-sakura&lt;/code&gt; という名前&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn6&quot; id=&quot;fnref6&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt;のディレクトリを作成し、移動します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ mkdir litellm-sakura
$ cd litellm-sakura
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;それから、LiteLLM 実行時に参照する設定ファイル config.yaml &lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn7&quot; id=&quot;fnref7&quot;&gt;[7]&lt;/a&gt;&lt;/sup&gt;を準備します。ファイル内容は以下のようにします。 &lt;a href=&quot;https://docs.litellm.ai/docs/providers/openai_compatible#advanced---disable-system-messages&quot;&gt;設定ファイルサンプル&lt;/a&gt;
を参考にしながらモデル名や、API エンドポイントを記載していきます。 &lt;code&gt;model_list:&lt;/code&gt; 以下は1つでも動作しますが、複数のモデルを用途に応じて切り替えられるようにしています。 &lt;code&gt;apikey&lt;/code&gt; には、さくらのAI Engine アクセストークンを入れますが、直接記述するのは様々な懸念があるため、環境変数 &lt;code&gt;SAKURA_API_KEY&lt;/code&gt; を参照するようにしています。&lt;/p&gt;
&lt;pre class=&quot;language-yaml&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-yaml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;model_list&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Coder&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;480B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A35B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Instruct&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;FP8
    &lt;span class=&quot;token key atrule&quot;&gt;litellm_params&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; openai/Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Coder&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;480B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A35B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Instruct&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;FP8
      &lt;span class=&quot;token key atrule&quot;&gt;api_base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.ai.sakura.ad.jp/v1
      &lt;span class=&quot;token key atrule&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; os.environ/SAKURA_API_KEY
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Coder&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;30B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A3B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Instruct
    &lt;span class=&quot;token key atrule&quot;&gt;litellm_params&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; openai/Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Coder&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;30B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A3B&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Instruct
      &lt;span class=&quot;token key atrule&quot;&gt;api_base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.ai.sakura.ad.jp/v1
      &lt;span class=&quot;token key atrule&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; os.environ/SAKURA_API_KEY
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; gpt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;oss&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;120b
    &lt;span class=&quot;token key atrule&quot;&gt;litellm_params&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; openai/gpt&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;oss&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;120b
      &lt;span class=&quot;token key atrule&quot;&gt;api_base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.ai.sakura.ad.jp/v1
      &lt;span class=&quot;token key atrule&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; os.environ/SAKURA_API_KEY
  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;model_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;0.6B
    &lt;span class=&quot;token key atrule&quot;&gt;litellm_params&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;token key atrule&quot;&gt;model&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; openai/Qwen3&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;0.6B
      &lt;span class=&quot;token key atrule&quot;&gt;api_base&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//api.ai.sakura.ad.jp/v1
      &lt;span class=&quot;token key atrule&quot;&gt;api_key&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; os.environ/SAKURA_API_KEY
&lt;span class=&quot;token key atrule&quot;&gt;litellm_settings&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;token key atrule&quot;&gt;drop_params&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean important&quot;&gt;true&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ファイルの準備が調ったら、次は Docker で LiteLLM を起動します。&lt;/p&gt;
&lt;p&gt;その前に、さくらの AI Engine のアクセストークンを環境変数 &lt;code&gt;SAKURA_API_KEY&lt;/code&gt; に入れておきます。 &lt;code&gt;read&lt;/code&gt; コマンドを使う場合は、次の様にコマンドを実行したあと、アクセストークンを入力してエンターキーを押します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ read -s SAKURA_API_KEY
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;入力後は &lt;code&gt;echo $SAKURA_API_KEY&lt;/code&gt; を実行し、適切にアクセストークンが表示されるか確認しておきます。&lt;/p&gt;
&lt;p&gt;それから、リファレス&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fn8&quot; id=&quot;fnref8&quot;&gt;[8]&lt;/a&gt;&lt;/sup&gt;を参考にして、以下のコマンドを実行し LiteLLM の proxy を動かします。ここでは &lt;code&gt;litellm-sakura&lt;/code&gt; という名前でコンテナを起動します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker run -d &#92;
    --name litellm-sakura &#92;
    -p 4000:4000 &#92;
    -e SAKURA_API_KEY=$SAKURA_API_KEY &#92;
    -v $(pwd)/config.yaml:/app/config.yaml &#92;
    docker.litellm.ai/berriai/litellm:main-latest &#92;
    --config /app/config.yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンド実行後、&lt;code&gt;docker ps&lt;/code&gt; コマンドを入力し、コンテナが正常も動作しているのを確認します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ docker ps
CONTAINER ID   IMAGE                                           COMMAND                   CREATED         STATUS         PORTS                                         NAMES
771696c38fb0   docker.litellm.ai/berriai/litellm:main-latest   &amp;quot;docker/prod_entrypo…&amp;quot;   9 seconds ago   Up 8 seconds   0.0.0.0:4000-&amp;gt;4000/tcp, [::]:4000-&amp;gt;4000/tcp   litellm-sakura
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;もし &lt;code&gt;docker ps&lt;/code&gt; で何も表示されなければコンテナは停止しています。 &lt;code&gt;docker logs litellm-sakura&lt;/code&gt; を実行すると、コンテナ実行から終了までのログが画面に出ますので、内容を確認して対処します。ちなみに私は初回、設定ファイルのパス指定を間違えてしまい、ログには &lt;code&gt;IsADirectoryError: [Errno 21] Is a directory: &#39;/app/config.yaml&#39;&lt;/code&gt; というエラーが出ていました。&lt;/p&gt;
&lt;p&gt;続けて、&lt;code&gt;curl&lt;/code&gt; コマンドで LiteLLM proxy （ローカルのport 4000で動作中）に対してリクエストを送り、さくらの AI Engineから応答があるかどうかを確認します。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ curl http://localhost:4000/v1/messages &#92;
    -H &amp;quot;Content-Type: application/json&amp;quot; &#92;
    -H &amp;quot;Authorization: Bearer dummy&amp;quot; &#92;
    -d &#39;{
      &amp;quot;model&amp;quot;: &amp;quot;Qwen3-Coder-30B-A3B-Instruct&amp;quot;,
      &amp;quot;max_tokens&amp;quot;: 50,
      &amp;quot;messages&amp;quot;: [{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;hello&amp;quot;}]
    }&#39;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;実行後、次のような応答があれば正常です。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{&amp;quot;id&amp;quot;:&amp;quot;chatcmpl-bed700d71de14efa8464ccbd53d94f5d&amp;quot;,&amp;quot;type&amp;quot;:&amp;quot;message&amp;quot;,&amp;quot;role&amp;quot;:&amp;quot;assistant&amp;quot;,&amp;quot;model&amp;quot;:&amp;quot;Qwen3-Coder-30B-A3B-Instruct&amp;quot;,&amp;quot;stop_sequence&amp;quot;:null,&amp;quot;usage&amp;quot;:{&amp;quot;input_tokens&amp;quot;:9,&amp;quot;output_tokens&amp;quot;:10,&amp;quot;total_tokens&amp;quot;:19},&amp;quot;content&amp;quot;:[{&amp;quot;type&amp;quot;:&amp;quot;text&amp;quot;,&amp;quot;text&amp;quot;:&amp;quot;Hello! How can I help you today?&amp;quot;}],&amp;quot;stop_reason&amp;quot;:&amp;quot;end_turn&amp;quot;}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;（モデル名はさくらの AI Engine上のもので、「content」には応答「Hello! How can I help you today?」が正常表示）&lt;/p&gt;
&lt;p&gt;もし応答がなければ、アクセストークンが正しいかどうか、あるいは Docker コンテナが定常に起動しているかどうか再確認します。&lt;/p&gt;
&lt;p&gt;それから環境変数を指定します。ここでは &lt;code&gt;env.sh&lt;/code&gt; を作ります。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export ANTHROPIC_BASE_URL=&amp;quot;http://localhost:4000&amp;quot;
export ANTHROPIC_AUTH_TOKEN=&amp;quot;sk-litellm-static-key&amp;quot;
export ANTHROPIC_MODEL=&amp;quot;Qwen3-Coder-480B-A35B-Instruct-FP8&amp;quot;
export ANTHROPIC_SMALL_FAST_MODEL=&amp;quot;Qwen3-0.6B&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;環境変数を読み込みます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ source ./env.sh
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;コマンド実行後、次のようにして、環境変数の内容を確認できます。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ echo $ANTHROPIC_BASE_URL
http://localhost:4000
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;これで準備は調いました。あとは &lt;code&gt;claude&lt;/code&gt; を実行したら自動的にさくらの AI Engine 側のモデルを参照した状態で起動できます。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zem.jp/img/Yt54RWB9JR-1844.avif 1844w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zem.jp/img/Yt54RWB9JR-1844.webp 1844w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zem.jp/img/Yt54RWB9JR-1844.png&quot; alt=&quot;&quot; width=&quot;1844&quot; height=&quot;930&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;もし &lt;code&gt;claude&lt;/code&gt; コマンド実行後、&lt;code&gt;Unable to connect to API (ConnectionRefused)&lt;/code&gt; と出る場合は、LiteLLM proxy が停止しているか、何か設定がおかしい可能性があります。手順を見直します。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zem.jp/img/S38fwrZE65-1362.avif 1362w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zem.jp/img/S38fwrZE65-1362.webp 1362w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zem.jp/img/S38fwrZE65-1362.png&quot; alt=&quot;&quot; width=&quot;1362&quot; height=&quot;342&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;`/status` を実行すると、どのモデルを参照しているのか見えます。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zem.jp/img/UbxduQCxE8-1828.avif 1828w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zem.jp/img/UbxduQCxE8-1828.webp 1828w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zem.jp/img/UbxduQCxE8-1828.png&quot; alt=&quot;&quot; width=&quot;1828&quot; height=&quot;770&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;モデルを切り替え得たい場合は &lt;code&gt;/model gpt-oss-120b&lt;/code&gt; のようにモデル名を指定します。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zem.jp/img/Wq1LT-VG5b-1098.avif 1098w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zem.jp/img/Wq1LT-VG5b-1098.webp 1098w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zem.jp/img/Wq1LT-VG5b-1098.png&quot; alt=&quot;&quot; width=&quot;1098&quot; height=&quot;250&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;あとは色々ためせます。ちなみに、ウェブの検索は出来ないもようでした。&lt;/p&gt;
&lt;p&gt;&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zem.jp/img/INcMv-sgM9-1822.avif 1822w&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zem.jp/img/INcMv-sgM9-1822.webp 1822w&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zem.jp/img/INcMv-sgM9-1822.png&quot; alt=&quot;&quot; width=&quot;1822&quot; height=&quot;1174&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Enjoy!&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;正確には、現時点では「使えなくなる状態だと分かった」であり、何かしら設定を追加したり別の方法によって検索可能となる可能性はあるが、未調査。 &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://code.claude.com/docs/ja/overview&quot;&gt;https://code.claude.com/docs/ja/overview&lt;/a&gt; &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://code.claude.com/docs/ja/llm-gateway &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn4&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://docs.litellm.ai/docs/providers/openai_compatible &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref4&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn5&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;GitHub: https://github.com/musistudio/claudecode-router &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref5&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn6&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;名前は何でも良いのですが、ここでは &lt;code&gt;litellm-sakura&lt;/code&gt; としました。 &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref6&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn7&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;config.yaml のリファレンス：QuickStart https://docs.litellm.ai/docs/proxy/configs &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref7&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn8&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;https://docs.litellm.ai/docs/proxy/docker_quick_start &lt;a href=&quot;https://zem.jp/articles/claude-code-litellm-sakura-ai-engine-setup.html#fnref8&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Bebop Style Development を公開しました</title>
    <link href="https://zem.jp/articles/launching-bebop-style-development.html" />
    <updated>2025-12-29T12:35:00Z</updated>
    <id>https://zem.jp/articles/launching-bebop-style-development.html</id>
    <content type="html">&lt;h1 id=&quot;bebop-style-development&quot;&gt;Bebop Style Development&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html&quot;&gt;先日の投稿&lt;/a&gt; の通り、&lt;a href=&quot;https://github.com/zembutsu/tsubame/&quot;&gt;Tsubame&lt;/a&gt; は、生成 AI を使っての開発（AI-Assisted Developmentに類すると考えられる）を行いました。&lt;/p&gt;
&lt;p&gt;私の開発スタイルは、Claude Code など自動的にコードを書かせるのではありません。ウェブブラウザ上のチャット画面での対話を通して、継続的な開発を行っています。Tsubame で試行錯誤していたプロセスを、手順としてまとめたのが、この &lt;a href=&quot;https://github.com/zembutsu/bebop-style-development&quot;&gt;Bebop Style Development&lt;/a&gt; です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/zembutsu/bebop-style-development&quot;&gt;https://github.com/zembutsu/bebop-style-development&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;なぜ Bebop なのかというと、なんとなく生成 AI との対話の「ノリ」が、音楽っぽいような印象を受けたからです。例えると、オーケストラとの違い。はじめから終わりまで、楽譜通りに演奏する大規模な音楽というよりは、なんか良い感じに、やってみる？というアプローチを例えたものです。&lt;/p&gt;
&lt;p&gt;おそらく、生成AIを使った何らかの開発、特にチャットを通しての場合、チャットが終わると意味が失われたり、継続することが困難という問題がありました。ですが、あらかじめ記録を「ログ」という形で残したり、ワークフローとして手順を作っておくと、別の会話ウインドウを開いたとしても、文脈を維持したまま作業を継続できています。&lt;/p&gt;
&lt;p&gt;実際、今日もこの Bebop Style Development 方式で開発を行い、問題無く作業が進行しています。次のリンク先にあるログは、Claude に対して、自由にこの開発方式にフィードバックして欲しいと依頼した結果です。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://gist.github.com/zembutsu/0f826b35195bc3d9e05404f131369b01&quot;&gt;https://gist.github.com/zembutsu/0f826b35195bc3d9e05404f131369b01&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;有る程度、利用者である私に忖度している書き方は感じますが、内容はさておき、開発としては機能していると考えられました。&lt;/p&gt;
&lt;p&gt;そのため、しばらくはプライベートリポジトリで運用していましたが、一応の機能することが確認できたため、本日リポジトリをパブリックにしました。&lt;/p&gt;
&lt;p&gt;まだ、細かな課題（定義が重すぎる、軽量版を作れないか）はいくつかありますが、徐々に運用しながら改善していきたいと考えています。&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>初めてのmacOSアプリ&quot;Tsubame&quot;を開発・リリース</title>
    <link href="https://zem.jp/articles/tsubame-first-binary.html" />
    <updated>2025-12-18T12:17:00Z</updated>
    <id>https://zem.jp/articles/tsubame-first-binary.html</id>
    <content type="html">&lt;h2 id=&quot;tsubame&quot;&gt;Tsubame とは&lt;/h2&gt;
&lt;p&gt;Tsubame（ &lt;a href=&quot;https://github.com/zembutsu/tsubame&quot;&gt;https://github.com/zembutsu/tsubame&lt;/a&gt; ） は、私が初めて作った macOS アプリです&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;。2025年11月から GitHub 上のリポジトリで開発を開始し、12月8日に macOS のバイナリリリース（Apple による Notarization 済み）に至りました。2012年にも Apple Developer Program に登録し、アプリ開発を試みていましたが挫折。積年を経て、ようやく開発に至りました。以下は、簡単なアプリの機能や、開発経緯を記録として残します。&lt;/p&gt;
&lt;h2 id=&quot;tsubame-2&quot;&gt;Tsubame は2画面のウインドウ操作を瞬時に行うアプリ&lt;/h2&gt;
&lt;p&gt;Tsubame は macOS のメニューバーに常駐するタイプのアプリです。機能としては、一般的に「ウインドウマネージャー」の領域であり、アプリとしては「作業効率化」にあたります。想定している利用者は、メインディスプレイと外部ディスプレイを分けて使っている方。特に、家や会社など場所によってディスプレイの位置が異なる方です。基本機能は主に2つ。1つはアプリのウインドウを、キーショートカットで瞬時に別のディスプレイに移動する機能。もう1つは、ウインドウ位置の記憶・復元です。&lt;/p&gt;
&lt;p&gt;アプリを違うディスプレイに移動するには、アプリを選択した状態でキーボード操作をします。デフォルトでは Ctrl-Cmd-→ で拡張画面に移動し、Ctrl-Cmd-←でメインウインドウに戻せます。移動後に微妙にポジションを調整したい場合は、Ctrl-Cmd-WASD（↑←↓→）で微調整も可能。つまり、キーボード操作をするだけ、トラックパッドやマウスを使わなくても瞬時にウインドウを移動できます。&lt;/p&gt;
&lt;p&gt;また、ウインドウの記憶・復元は自動でも手動でも行えます。たとえば、外部ディスプレイとのケーブルが抜けたり、電源が節電モードで切れたりすると、拡張ディスプレイで表示していたアプリはメイン画面に移動させられます。しかし、再び拡張ディスプレイの接続が復帰してもウインドウはメインに残ったまま。通常であれば、何もないディスプレイに手動でウインドウを再配置する必要がありました。Tsubame はウインドウ位置を自動記録していますので、拡張ディスプレイとの接続が切れても、再認識したあとは自動的にウインドウを再配置します。&lt;/p&gt;
&lt;h2 id=&quot;&quot;&gt;どうして作ったのか&lt;/h2&gt;
&lt;p&gt;そもそも、なぜ Tsubame を作ったかといえば、私自身が困った・面倒だと思っていたからです。私が困っていたのは2画面での作業時。ふだん、メイン画面と拡張画面を横に並べて使っています。おそらく私だけの環境かもしれませんが、macOS がスリープ状態から復帰したら、拡張画面で操作していたウインドウが強制的にメイン画面に戻ってしまう困りごとがずっとありました。拡張画面側のディスプレイの電源復帰に時間がかかるか、あるいはディスプレイを認識するまでに時間がかかるのでしょうか。&lt;/p&gt;
&lt;p&gt;いずれにしろ、メイン画面のウインドウを、毎回トラックパッドで移動する必要がありました。私は常に10以上のウインドウを動かしていますので、元の自分の快適だと思う場所に戻すという手間がありました。本当毎回面倒ですし、思っていたベストポジションにウインドウを調整するのも面倒でした。&lt;/p&gt;
&lt;h2 id=&quot;-2&quot;&gt;どのようにして作ったのか&lt;/h2&gt;
&lt;p&gt;当初、このアプリは単純なディスプレイ間の移動機能だけを備えていました。キーショートカットによって瞬時に移動できる。ただそれだけの、シンプルなアプリ。当時の開発コードは Window Smart Mover という名称です。Tsubame の GitHub リポジトリ内&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fn2&quot; id=&quot;fnref2&quot;&gt;[2]&lt;/a&gt;&lt;/sup&gt;にも、開発当初の名残が今も残っています。&lt;/p&gt;
&lt;p&gt;そして、いよいよアプリが動き意気揚々。これで全て解決したと思っていたのですが、この問題は根本的な私の悩みを解決しないのだと気づきました。&lt;/p&gt;
&lt;p&gt;確かに、拡張ディスプレイにウインドウは瞬時に動かせるようになりました。キーボード操作だけで、本当に楽です。ですが、拡張ディスプレイに自動的にウインドウが再配置される機能こそが、私が本当に欲しかったものだと気づいたのです。そもそも、自動再配置できれば、キーボード操作で拡張ディスプレイにアプリを移動する手間すら不要になります。そして、ようやく主要機能をキーボード操作と自動復元の2つに絞っての開発がスタートしました。&lt;/p&gt;
&lt;p&gt;ちなみに、似たようなツールとして Rectangle （https://rectangleapp.com/）や  Magnet（https://magnet.crowdcafe.com/）は認識していました。ですが、どちらも私の求めている機能より多機能すぎたり学習コストが高そうだぞと。あるいはアプリは便利そうですが、ソースコードは公開されておらず、中身が見えなくて不安だという個人的な懸念もありました。&lt;/p&gt;
&lt;p&gt;そして、たまたま Claude （ブラウザ版のチャット）を通して Xcode で開発できそうだと認識。あえて学習を通した車輪の再発明をしてみようと、勉強がてら取り組もうとしたのがスタート地点でした。その後、紆余曲折ありましたが、おおよそ1ヶ月でのリリースです。開発には Claude を使いました。Claude Code ではなく、普通にブラウザでの会話を通したのみです。何か開発用のツール導入や、生成AIサービスのAPI利用もありません。また、Vibe コーディングやspecのような定義をするような手法とも異なります。&lt;/p&gt;
&lt;p&gt;基本的な進め方は、私がClaudeに指示したり質問したり、表示された内容を元に開発を進めました。そのため、もしかしたら、一般的な AI を使った開発手法とは異なり、AI 支援開発&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fn3&quot; id=&quot;fnref3&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;と呼ばれる類型なのかなと思います。思いますというおは、既存の手法を意識しておらず、Claude との会話を通してアプリの完成に至ったつもり。具体的な開発手法については、また改めて整理して書こうと思います。&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;なにをもって「アプリ」とするかですが、SwiftUI で作ったバイナリ形式のアプリは、初めてです。 &lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn2&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;&lt;a href=&quot;https://github.com/zembutsu/tsubame/tree/main/WindowSmartMover&quot;&gt;https://github.com/zembutsu/tsubame/tree/main/WindowSmartMover&lt;/a&gt; &lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fnref2&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id=&quot;fn3&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;AI-Assisted Development &lt;a href=&quot;https://zem.jp/articles/tsubame-first-binary.html#fnref3&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Close the world, Open the next.</title>
    <link href="https://zem.jp/articles/open-the-next.html" />
    <updated>2025-11-02T12:00:00Z</updated>
    <id>https://zem.jp/articles/open-the-next.html</id>
    <content type="html">&lt;p&gt;Close the world, Open the next.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a href=&quot;https://zem.jp/articles/open-the-next.html#fn1&quot; id=&quot;fnref1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;私(@zembutsu)の、個人的な取り組み・記録を公開する場所。&lt;/p&gt;
&lt;p&gt;散らばった情報のカケラを整理する場所。&lt;/p&gt;
&lt;hr class=&quot;footnotes-sep&quot;&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;&lt;p&gt;PlayStation の &amp;quot;Serial Experiments Lain&amp;quot; のパッケージに掲載された文字。 &lt;a href=&quot;https://zem.jp/articles/open-the-next.html#fnref1&quot; class=&quot;footnote-backref&quot;&gt;↩︎&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
</feed>