Stable Diffusion デスクトップアプリ「Sodalite」を開発した
Stable Diffusion で画像を生成する方法は数多くありますが、Web UI 系のツールは Python 環境の構築や依存関係の管理が煩雑になりやすいです。
もっと手軽に、インストーラーをダウンロードするだけで使えるデスクトップアプリが欲しくなり、Sodalite を一から開発しました。
Stable Diffusion で画像を生成する方法は数多くありますが、Web UI 系のツールは Python 環境の構築や依存関係の管理が煩雑になりやすいです。
もっと手軽に、インストーラーをダウンロードするだけで使えるデスクトップアプリが欲しくなり、Sodalite を一から開発しました。
Claude Code CLI (claude) は、Anthropic 純正のモデルだけでなく、OpenRouter が提供する
Anthropic Messages API 互換エンドポイント("Anthropic Skin")を使うことで、任意のモデルを
バックエンドとして動かせる。今回は会話のメインモデルに z-ai/glm-5.2、タイトル生成などの
軽量な背景タスク用に z-ai/glm-4.7-flash を割り当てる設定を試したので、そのやり方をまとめる。
参考: https://openrouter.ai/docs/cookbook/coding-agents/claude-code-integration
$env:OPENROUTER_API_KEY に OpenRouter の API キーが設定済みであること。claude.ai アカウントでログイン済みでも、環境変数による認証があればそちらが
優先される。その際 ⚠ claude.ai connectors are disabled ... という警告が出るが、動作には
影響しない。| 変数 | 値 | 備考 |
|---|---|---|
ANTHROPIC_BASE_URL | https://openrouter.ai/api | OpenRouter の Anthropic 互換エンドポイント |
ANTHROPIC_AUTH_TOKEN | OpenRouter の API キー | Authorization: Bearer として送られる |
ANTHROPIC_API_KEY | ""(明示的に空文字) | 未設定/非空だと認証方式が競合してエラーになる |
ANTHROPIC_MODEL | z-ai/glm-5.2 | メインの会話モデル。OpenRouter 上のモデル ID をそのまま指定する |
ANTHROPIC_SMALL_FAST_MODEL | z-ai/glm-4.7-flash | タイトル生成など軽量な背景タスク用のサブモデル |
ANTHROPIC_MODEL はメインの会話モデルのみを制御する。タイトル生成や auto-mode 判定など、
Claude Code が内部的に使う軽量・高速なサブモデルは ANTHROPIC_SMALL_FAST_MODEL で指定する。
この変数を設定しておけば、それだけで軽量タスク用のモデルを確実に切り替えられる。
リポジトリの .claude/settings.local.json に以下を設定する。
{
"env": {
"ANTHROPIC_BASE_URL": "https://openrouter.ai/api",
"ANTHROPIC_API_KEY": "",
"ANTHROPIC_MODEL": "z-ai/glm-5.2",
"ANTHROPIC_SMALL_FAST_MODEL": "z-ai/glm-4.7-flash"
}
}
ANTHROPIC_AUTH_TOKEN(秘密情報)はファイルに書かず、シェル側で OPENROUTER_API_KEY から
供給する。PowerShell プロファイル($PROFILE)に以下を一度追加しておけば、以後シェルを開くたびに
自動で設定される。
$env:ANTHROPIC_AUTH_TOKEN = $env:OPENROUTER_API_KEY
bash/zsh の場合は ~/.bashrc や ~/.zshrc に:
export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"
この状態でこのディレクトリ内で claude -p "..." を実行すると、.claude/settings.local.json
の設定が自動的に読み込まれ、OpenRouter 経由でメイン/サブ両モデルが使われる。他のプロジェクトの
Claude Code 実行には影響しない。
シェルプロファイルを変更したくない場合、その場で環境変数を指定して実行する。
PowerShell:
$env:ANTHROPIC_BASE_URL = "https://openrouter.ai/api"
$env:ANTHROPIC_AUTH_TOKEN = $env:OPENROUTER_API_KEY
$env:ANTHROPIC_API_KEY = ""
$env:ANTHROPIC_MODEL = "z-ai/glm-5.2"
$env:ANTHROPIC_SMALL_FAST_MODEL = "z-ai/glm-4.7-flash"
claude -p "1+1は?"
bash:
ANTHROPIC_BASE_URL="https://openrouter.ai/api" \
ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY" \
ANTHROPIC_API_KEY="" \
ANTHROPIC_MODEL="z-ai/glm-5.2" \
ANTHROPIC_SMALL_FAST_MODEL="z-ai/glm-4.7-flash" \
claude -p "1+1は?"
上記の変数を Windows のユーザー環境変数として永続化すれば、どのターミナル・どのプロジェクトでも デフォルトで OpenRouter/GLM 経由になる。ただし他のプロジェクトで通常の Claude(Anthropic) を 使うつもりの操作にも影響してしまうため、意図せず全体のデフォルトを変えたくない場合は方法A/Bを推奨。
以下のコマンドで応答および課金ログ (modelUsage) に z-ai/glm-5.2 が記録されることを確認した。
claude -p "Reply with exactly: OK-GLM-TEST" --output-format json
{
"result": "OK-GLM-TEST",
"modelUsage": {
"z-ai/glm-5.2": { "inputTokens": 3272, "outputTokens": 8, "costUSD": 0.028336 }
}
}
また、少し長めのプロンプトで --debug all を付けて実行すると、メインモデルとサブモデルへの
ディスパッチが両方とも実際に発生することも確認できた。
[API:timing] dispatching to firstParty model=z-ai/glm-4.7-flash
[API:timing] dispatching to firstParty model=z-ai/glm-5.2
1 回のプロンプトに対し、軽量タスクは z-ai/glm-4.7-flash、本編の応答は z-ai/glm-5.2 と、
モデルが正しく使い分けられている。
対話型の claude セッション(VS Code から開いた場合や TTY 上で直接起動した場合)では、軽く
入力しただけで OpenRouter の Activity ログ上に同一分内で 13 回もの API 呼び出しが記録された。
そのうち 12 回はサブモデル(GLM 4.7 Flash)宛ての小さな呼び出しで、最後の 1 回だけメインモデル
(GLM 5.2)による本編の応答だった。合計コストは約 $0.0094 に収まっている。
一方、claude -p(非対話・print モード)による単発実行では、この増殖はほぼ発生しないことを
確認済み。コストを抑えたい用途では -p を使う方が安全。対話型セッションを常用する場合は、
ANTHROPIC_SMALL_FAST_MODEL を設定して安価なモデルにリクエストを流しつつ、OpenRouter の
Activity ダッシュボードで消費を監視するとよい。
⚠ claude.ai connectors are disabled because ANTHROPIC_API_KEY or another auth source is set...
という警告は無視してよい(claude.ai のコネクタ機能が無効になるだけで、API 呼び出し自体は成功する)。ANTHROPIC_API_KEY を空文字ではなく未設定のままにすると認証方式が曖昧になりエラーになることがある。
必ず "" を明示的に設定すること。ANTHROPIC_MODEL を OpenRouter 上のモデル ID
(例: anthropic/claude-opus-4-8, openai/gpt-5 など)に変更するだけでよい。ENABLE_TOOL_SEARCH)は非 Anthropic ホストではデフォルト無効になる。
必要なら ENABLE_TOOL_SEARCH=true を追加する。AI 開発の現場では、モデルそのものよりも API 仕様の違いに悩まされることが増えている。
Claude Code は Anthropic Messages API を利用する。OpenAI 系ツールは Chat Completions API や Responses API を利用する。Gemini は独自 API を持ち、ローカル LLM 環境では Ollama や LM Studio がOpenAI 互換 API を提供する。
利用したいモデルは存在するにもかかわらず、API 仕様が違うために接続できない。SDK を書き換え、変換レイヤーを実装し、環境ごとに設定を分ける必要がある。
こうした問題を解決するのが llmglot である。
GitHub: https://github.com/Himeyama/llmglot
llmglot は、複数の LLM API を相互変換するプロキシサーバーである。
Anthropic Messages API、OpenAI Responses API、OpenAI Chat Completions API、Gemini API などを受け取り、上流の API へ適切に変換して転送する。
つまり、クライアントが要求するAPI仕様と、実際に利用したいモデルのAPI仕様が一致していなくても利用できる。
クライアント側としては、
などに対応している。
接続先としては、
などが利用できる。
例えば、
といった接続が可能になる。
llmglot の用途の一つが、Claude Code とローカル LLM の接続である。
例えば Ollama を利用している場合、
CHAT_BASE_URL=http://localhost:11434/v1 llmglot
として起動する。
その後、Claude Code の接続先を llmglot へ変更するだけで、Claude Code からローカル LLM を利用できる。
高価なAPIを利用せずにコードエージェントを試せる点は非常に魅力的である。
(補足: Ollama は Messages API に対応しているので実はプロキシは不要である)
近年は Responses API を利用するツールが増えている。
llmglot は /v1/responses エンドポイントを実装しており、HTTP だけでなく WebSocket にも対応している。
そのため、Codex CLI のような Responses API ベースのクライアントとも接続しやすい。
llmglot にはログ表示機能が搭載されている。
確認できる情報は、
などである。
複数の LLM を利用する環境では、利用状況を一元管理できるメリットは大きい。
ここで気になるのが LiteLLM との違いである。
どちらも LLM の間に入るソフトウェアだが、目指している方向は大きく異なる。
LiteLLM は多数の LLM プロバイダーを OpenAI 形式に統一する。
つまり、
アプリ
↓
LiteLLM
↓
各LLMプロバイダー
という構成である。
アプリケーション開発者が統一 API を利用するための仕組みと言える。
一方 llmglot は、
Claude Code
Codex CLI
Gemini SDK
↓
llmglot
↓
各 LLM プロバイダー
という構成になる。
クライアント側の API 仕様を変換することが目的である。
Claude Code は Anthropic Messages API を利用する。
LiteLLM は基本的に OpenAI 互換 API を中心としているため、そのままClaude Code を接続することは難しい。
一方 llmglot は Anthropic Messages API を直接受け付ける。
そのため、
Claude Code
↓
llmglot
↓
Ollama
という構成が実現できる。
これは llmglot の非常に大きな特徴である。
LiteLLM が向いているのは、
である。
一方、llmglot が向いているのは、
である。
LLM の世界ではモデルそのものよりも API の違いが問題になる場面が増えている。
Claude Code を使いたいが Ollama を利用したい。OpenAI SDK を使いたいが Gemini を利用したい。こうした要求は今後さらに増えていくだろう。
llmglot は、その間に立って API 仕様の違いを吸収する。
LiteLLM が「開発者向けの統一 API」であるのに対し、llmglot は「クライアント互換プロキシ」と言える。
2026年6月、Microsoftは Coreutils for Windows を正式に公開した。
winget install Microsoft.Coreutils
このコマンドでインストールできる Microsoft.Coreutils は、LinuxやmacOSで日常的に利用される ls、cp、rm、cat などのUNIX系コマンドを、Windows上でネイティブ実行できるようにするMicrosoft公式プロジェクトである。
本記事では、プロジェクトの概要、対応コマンド、制限事項、WSLやPowerShell との違いを整理する。
Microsoft.Coreutilsは、MicrosoftがメンテナンスするWindows向けのコマンドラインツール群である。
内部的には、
をベースに構築されており、Rust で実装されている。
Microsoft はこのプロジェクトの目的を、
Linux、macOS、WSL、コンテナ、Windowsを行き来する開発者の摩擦を減らすこと
と説明。
WinGet から簡単に導入可能である。
winget install Microsoft.Coreutils
WinGetはWindows標準のパッケージマネージャーであり、指定したパッケージを自動的にダウンロード・インストール可能。
インストール後は通常のコマンドとして利用可能。
ls
cat file.txt
grep keyword log.txt
cp source.txt backup.txt
代表的なコマンドは以下の通り。
| 分類 | コマンド例 |
|---|---|
| ファイル一覧 | ls |
| ファイルコピー | cp |
| ファイル移動 | mv |
| ファイル削除 | rm |
| 内容表示 | cat |
| 作業ディレクトリ | pwd |
| ディレクトリ作成 | mkdir |
| スリープ | sleep |
| パイプ処理 | tee |
| 検索 | grep, find |
Linux利用者であれば見慣れたコマンドがそのまま利用可。
ここが最大の注意点!
PowerShell には既に同名のエイリアスや組み込みコマンドが存在する。
例:
| コマンド | 問題 |
|---|---|
| ls | PowerShellエイリアスと衝突 |
| cp | Copy-Itemと衝突 |
| cat | Get-Contentと衝突 |
| rm | Remove-Itemと衝突 |
| pwd | Get-Locationと衝突 |
そのため、
ls
を実行しても、必ずしも Coreutils 版が呼ばれるわけではない。
Microsoft は PowerShell 7.4 以降の利用を推奨している。
Linux 互換を目指しているものの、Windowsの仕組みによる制限が存在する。
Linuxの
kill
SIGTERM
SIGKILL
の仕組みはWindowsに存在しない。
そのため、
kill
timeout
は現時点で提供されない。
Linux:
grep error log.txt > /dev/null
Windows:
grep error log.txt > NUL
となる。
Windows は ACL ベースの権限管理である。
そのため、
chmod
chown
chgrp
などのコマンドは提供されない。
読み取りは可能だが、新規作成には
が必要である。
Microsoft は一部コマンドを意図的に除外している。
よく比較されるのが WSL(Windows Subsystem for Linux)である。
| 項目 | Microsoft.Coreutils | WSL |
|---|---|---|
| 導入コスト | 非常に低い | Linux環境構築が必要 |
| 起動速度 | ネイティブ | 仮想環境層あり |
| Linux互換性 | 一部 | 非常に高い |
| Bash環境 | なし | あり |
| apt利用 | 不可 | 可能 |
| シェルスクリプト互換性 | 限定的 | 高い |
WSL は「Linux 環境そのもの」だが、Coreutils は「Windows 上で Linux 風コマンドを使うためのツール集」である。
日々の業務で Python スクリプトを用いてデータ変換の自動化を行うと、次のような課題に直面することが多い。
Makefile は「依存関係」と「差分だけの再実行(インクリメンタルビルド)」を標準機能として備え、これらの課題を小さな記述で解決できる道具である。
Make は「依存関係がターゲットより新しいときにだけレシピを実行」する。これにより、元データや Python スクリプトを更新した場合に、必要な箇所のみが自動的に再実行される。
以下は raw データをクリーニングし、集計レポートを作る一連の処理を差分実行する例である。
# Makefile
SHELL := bash
.SHELLFLAGS := -eu -o pipefail -c
.DELETE_ON_ERROR:
.ONESHELL:
.DEFAULT_GOAL := all
RAW_DIR := data/raw
CLEAN_DIR := data/clean
OUT_DIR := output
RAW := $(wildcard $(RAW_DIR)/*.csv)
CLEAN := $(patsubst $(RAW_DIR)/%.csv,$(CLEAN_DIR)/%.csv,$(RAW))
REPORT := $(OUT_DIR)/report.csv
# ディレクトリは順序限定依存(存在しなければ作るが、更新判定には使わない)
$(CLEAN_DIR) $(OUT_DIR):
mkdir -p $@
# 集計レポートはクリーン済み CSV と集計スクリプトに依存
$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR)
python scripts/aggregate.py -i $(CLEAN_DIR) -o $@
# 各 raw CSV から対応する clean CSV を生成
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@
.PHONY: all clean status
all: $(REPORT)
clean:
rm -rf $(CLEAN_DIR) $(OUT_DIR)
# 何が再ビルド対象かを確認するヘルパ
status:
@echo "RAW : $(RAW)"
@echo "CLEAN : $(CLEAN)"
@echo "REPORT: $(REPORT)"
@echo
@echo "Dry-run (what would run):"
@$(MAKE) -n all
この構成により次が実現できる。
# 初回(すべて生成)
make -j
# 一部の raw が更新(そのファイルのクリーンとレポートのみ再実行)
touch data/raw/a.csv
make -j
# クリーニングスクリプトが更新(全クリーンとレポートを再実行)
touch scripts/clean.py
make -j
# 集計スクリプトが更新(レポートのみ再実行)
touch scripts/aggregate.py
make
「何が走るか」を事前確認するには make -n が有効である。
例(簡便策):
PY_SRCS := $(wildcard scripts/**/*.py) $(wildcard scripts/*.py)
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv $(PY_SRCS) | $(CLEAN_DIR)
python scripts/clean.py -i $< -o $@
make -j により独立したファイル変換を並列化できる。データ点数が多いほど効果が高い。| dir)で扱い、無駄な再ビルドを避ける。.DELETE_ON_ERROR を有効化する。.DEFAULT_GOAL := all で標準化し、make 一発で動かせるようにする。make -n(実行せず表示)、make --trace(どの判定で動くか表示)、make -d(詳細ログ)を使う。.PHONY: clean とし、生成物だけを削除するよう注意する。Python の実行環境も Make で管理できる。
VENV := .venv
PY := $(VENV)/bin/python
$(VENV)/bin/python: requirements.txt
python3 -m venv $(VENV)
$(VENV)/bin/pip install -r requirements.txt
touch $@
# 以降のレシピで $(PY) を使う
$(CLEAN_DIR)/%.csv: $(RAW_DIR)/%.csv scripts/clean.py | $(CLEAN_DIR) $(VENV)/bin/python
$(PY) scripts/clean.py -i $< -o $@
$(REPORT): $(CLEAN) scripts/aggregate.py | $(OUT_DIR) $(VENV)/bin/python
$(PY) scripts/aggregate.py -i $(CLEAN_DIR) -o $@
requirements.txt を更新すると必要な範囲でのみ再セットアップされる。
Anthropic API の /v1/models エンドポイントを使うと、利用可能な Claude モデルの一覧とその仕様をプログラムから取得できる。
さくらのレンタルサーバー「ライトプラン」は、36ヶ月一括払いで 月額121円 という破格の安さだ。(12ヶ月一括の場合は月165円) 静的ファイルのホスティングや CGI 用途としては十分で、個人用途のストレージとして気軽に使える。
ただし、割り当てられるドメインは ユーザー名.sakura.ne.jp のサブドメインになるため、
独自ドメインで特定のパスに紐づけたい場合は一工夫が必要になる。
https://app.example.com にアクセスすると、
https://sakurauser.sakura.ne.jp/app/ のコンテンツが
URL を変えずに 表示されるようにする。
DNS の CNAME レコードはホスト名しか指定できず、
/app/ のような パスを含む URL は指定できない。
リダイレクト (301) でも実現できるが、
ブラウザのアドレスバーの URL が sakurauser.sakura.ne.jp/flower/ に変わってしまう。
Cloudflare Workers を使った透過プロキシなら、
URL を app.example.com のまま維持できる。
example.com) を登録済みであることstorage-proxy)Deploy 後、Edit code をクリックし、 以下のコードに全て置き換える。
export default {
async fetch(request) {
const url = new URL(request.url);
const target = new URL("https://sakurauser.sakura.ne.jp");
target.pathname = "/app" + url.pathname;
target.search = url.search;
const newRequest = new Request(target.toString(), {
method: request.method,
headers: request.headers,
body: request.body,
});
const response = await fetch(newRequest);
const newHeaders = new Headers(response.headers);
newHeaders.delete("content-security-policy");
newHeaders.delete("x-frame-options");
return new Response(response.body, {
status: response.status,
headers: newHeaders,
});
}
};
このブログを AWS S3 から Cloudflare Pages へ移行した。これまでは S3 で静的ホスティングを行い、CloudFront を通じて配信していたが、管理の簡素化とパフォーマンス向上のために Cloudflare Pages を採用することにした。
現代の UI デザインでは「余白は 8 の倍数で設定する」というルールがよく用いられる。これは単なる慣習ではなく、画面密度・タイポグラフィ・スケールの数学的整合性に裏付けられた経験則である。
Amazon S3 Files は、S3 バケットを NFS ファイルシステムとして EC2 などのコンピュートリソースに直接マウントできるサービスである。データは S3 に保持されたまま、通常のファイル操作 (ls、cp、cat など) で読み書きできる。