はじめに

kanade — 奏 は Windows 端末群の管理システムです。operator はひとつの CLI / SPA から、数百台規模の PC に対してスクリプト実行・ソフトウェア配布・インベントリ収集・ライブのパフォーマンスデータ取得を一気にこなせます。構成要素:

コンポーネント役割
kanade-agent管理対象 PC 上で動く Windows サービス。NATS を購読し、コマンドを実行して結果を送り返します。
kanade-backendHTTP API + projector。状態を永続化し、SPA を配信し、operator 用エンドポイントを公開します。
kanade-clientオプションの Tauri デスクトップアプリ。エンドユーザー向け UI。
NATS serverコマンドのファンアウトと結果集約を担うメッセージブローカー。agent は NATS だけと話し、backend も NATS から読みます。
kanade CLIoperator が使うコマンドライン。バイナリの publish、ジョブの起動、状態の照会を行います。

このサイトは 2 種類の読者を想定しています:

  • operator (kanade fleet の運用者) — 各端末に ssh せずに各コンポーネントをアップデートする方法 (agent 経由のアップデート 参照)。
  • 開発者 (agent が実行する PowerShell ジョブを書く人) — 何が動いて何が動かないか、最近の agent バージョンで何が変わったか (agent 向けスクリプトを書く 参照)。

詳細なプロトコル / on-wire 仕様は Spec にあります (旧 single-page ドキュメント。docs サイトが整うにつれて章別に分割予定)。

開発者クイックスタート

このガイドでは、ローカルの kanade 開発環境をセットアップして起動する手順を説明します。

1. Prerequisites

開始する前に、Windows マシンに以下がインストールされていることを確認してください。

  • Rust toolchain (stable channel)
  • cargo-make (run cargo install --force cargo-make)
  • bun (for SPA dependency management and build execution)
  • gsudo (for local service deployment tests)
  • nats-server (runnable from PATH)

2. One-Time Setup

ワークスペースのルートで以下のコマンドを実行し、git の pre-push フックを登録し、apm.yml で定義されたエージェントスキルをインストールします。

cargo make setup

3. Launching the Dev Sandbox

単一のコマンドを使用するだけで、ローカルホスト上に完全に分離されたマルチコンポーネント開発スタックを起動できます。

cargo make dev

このタスクは、ループバックサンドボックス内で以下のサービスを並行して実行します。

  1. nats-dev: Unauthenticated NATS broker listening on port 4223.
  2. backend-dev: Dev API server listening on port 8081 with auth disabled.
  3. agent-dev: Local dev agent talking to the dev NATS broker on 4223.
  4. web-dev: Vite dev server for the React SPA listening on http://localhost:5173.

Ctrl+C を押すことで、すべてのコンポーネントをクリーンに終了できます。

4. Multi-Agent Fleet Simulation

複数のマシンを管理しているときにのみ発生する動作(並行実行結果のプロジェクションや ID 衝突など)をデバッグするために、マルチエージェントサンドボックスを起動できます。

cargo make dev-fleet

これにより、NATS ブローカー、バックエンド、SPA に加えて、独立した ID(dev-pc-1dev-pc-2dev-pc-3)と隔離された状態データベースを持つ 3 つの個別開発用エージェントが起動します。

5. Local Deploy Testing

Windows サービスとしてコンポーネントをインストールする全ライフサイクル(本番環境の模倣)をテストしたい場合は、ローカルデプロイスクリプトを使用します。

# Installs CLI, agent, backend, and NATS services locally via gsudo elevation
cargo make local-deploy

デプロイ後、実際の Windows サービスを確認して対話できます。完了したら、以下のタスクを使用してサービスを停止し、きれいに削除します。

cargo make local-undeploy

システムアーキテクチャ

kanade は、数百台の Windows エンドポイントを並行して、安全に、そして非同期で管理するように設計されています。

Component Topology

システムは 5 つの主要コンポーネントで構成されており、イベント駆動型の pub/sub 構造を介して調整されます。

graph TD
    subgraph Operator Session
        CLI[kanade CLI]
        SPA[React SPA]
    end

    subgraph Server Infrastructure
        Backend[kanade-backend]
        NATS[NATS Broker / JetStream]
    end

    subgraph Windows Endpoints
        Agent1[kanade-agent PC-1]
        Agent2[kanade-agent PC-2]
        Client[kanade-client Tauri App]
    end

    CLI -->|Command / Query API| Backend
    SPA -->|REST / WebSockets| Backend
    Backend <-->|State/PubSub| NATS
    Agent1 <-->|NATS-only Connection| NATS
    Agent2 <-->|NATS-only Connection| NATS
    Client <-->|Tauri IPC| Agent1

1. kanade-agent

各管理対象ホスト上で動作する高性能な Windows サービスです。

  • Role: Core executor.
  • Communication: Establishes an outbound-only NATS connection. It does not open any inbound ports, making it firewall-friendly.
  • Capabilities: Launches secure, isolated PowerShell subprocesses, inventories hardware/software specs, streams live performance data (CPU, RSS memory, disk I/O), and manages local packages.

2. kanade-backend

中央の HTTP API およびプロジェクションサーバーです。

  • Role: Coordinates commands, processes incoming telemetry, and hosts the operator Web interface.
  • State management: Persists events, activity logs, and status records in a localized SQLite database.
  • Projector pattern: Subscribes to the NATS command-response stream, parses incoming payloads, and projects them into state tables in real-time.

3. NATS Broker (with JetStream)

フリート全体のメッセージ転送レイヤーです。

  • Role: Lightweight, high-throughput message broker.
  • JetStream: Retains command streams, job registrations, and file storage (using NATS Object Store buckets for distributing packages and agent scripts).
  • Isolation: Decouples the backend from the agents. If the backend is offline or restarting, agents continue execution and cache outbox records, pushing them once connection resumes.

4. kanade-client

エンドポイント上のログインユーザーのデスクトップセッションで動作する、オプションの Tauri デスクトップアプリケーションです。

  • Role: Provides end-user interaction (e.g., prompt dialogs, notifications, or a user-facing dashboard).
  • Communication: Shares state with the local kanade-agent via secured local IPC mechanisms.

5. kanade CLI

オペレーター向けの主要なコマンドラインツールです。

  • Role: Packages and publishes software updates, submits and executes job manifests, and queries live fleet inventory from the command-line.

Security & Reliability Design

Outbound-only Connections

エージェントは、アウトバウンド TCP 接続を開始することによってのみ NATS ブローカーと通信します。エンドポイント側でファイアウォールポートを開く必要がないため、横移動や外部からのポートスキャンのリスクを排除できます。

Agent Job Sandboxing

When executing scripts, the agent stages commands in %ProgramData%\Kanade\agent-scripts and executes them using customized launcher templates. Administrators can enforce identity configurations via job manifests, specifying run_as: system (for elevated system management) or run_as: user (to run safely under the active user's credentials with restricted directory ACLs).

運用概要

kanade の day-2 運用は 2 つのフローに分かれます:

  1. 直接インストール — まっさらなホストにバイナリと config を置いて Windows サービスを登録します。最初の agent、最初の backend、NATS サーバーをブートストラップするときに使います。スクリプト: scripts/deploy/agent.ps1scripts/deploy/backend.ps1scripts/deploy/nats.ps1。対象ホスト上で手動で実行します。

  2. agent 経由のアップデート — agent がいったん動き出せば、その agent 自身が ssh / RDP なしで同じホスト上の他コンポーネントをインストール・更新できます。operator はバイナリとスクリプト本体をブローカーに publish し、ジョブを起動。agent が fetch・検証・swap・サービス再起動を行います。day-2 運用の大半はこれ。

agent 経由フローの形は、何をアップデートする場合でも同じです:

operator host ─► kanade CLI ─► NATS broker ─► agent (on target host)
                    │                              │
                    ├── publish binary ────────────► fetches from
                    │   to OBJECT_APP_PACKAGES        OBJECT_APP_PACKAGES
                    ├── publish script ────────────► fetches from
                    │   to OBJECT_SCRIPTS             OBJECT_SCRIPTS
                    ├── register / update job ─────► reads job manifest
                    │                                 from `jobs` KV
                    └── exec job ──────────────────► PowerShell child
                                                      runs the script

コンポーネント別ガイド:

  • kanade-backend — HTTP / projector バイナリ
  • kanade-client — Tauri 製のエンドユーザーアプリ
  • NATS サーバー — ブローカー本体 (はい、ブローカー越しにブローカーをアップデートできます)
  • kanade-agent 自身 — agent の self-update 経路 (他 3 つと違い、汎用の OBJECT_APP_PACKAGES + script ペアではなく専用の rollout バケットを使います)

インストールとデプロイ

このセクションでは、本番環境またはステージング環境で kanade コンポーネントをネイティブの Windows サービスとしてブートストラップする方法を詳しく説明します。

Deployment Model

本番ホストと管理対象エンドポイントは、kanade コンポーネントをバックグラウンドの Windows サービスとして実行します。これにより、高可用性と自動起動が保証されます。

サービス名トリプル / バイナリ設定ソース典型的なターゲット
KanadeNatsnats-server.exe保護されたレジストリ / レジストリ保存の CLI フラグ中央サーバー
KanadeBackendkanade-backend.exe保護されたレジストリ / 設定ファイル中央サーバー
KanadeAgentkanade-agent.exe保護されたレジストリ / ローカル状態 DB管理対象エンドポイント

1. Prerequisites

  • Host OS: Windows 10/11 or Windows Server 2016+.
  • gsudo: Required to perform elevated installations from standard user shells (or run commands from an Administrator-level PowerShell prompt).
  • Network Routing: Managed endpoints must be able to reach the NATS server port (default 4222) over TCP.

2. Setting Up the NATS Server (Broker)

NATS サーバーはメッセージングのコアとして機能します。

  1. Stage the deployment bundle using scripts/build-release.ps1 -Roles nats.
  2. Deploy the service with elevation:
    # Elevated PowerShell prompt
    & "dist\nats\deploy-nats.ps1" -NatsToken "your-secure-nats-token" -Recreate
    

これにより、KanadeNats サービスがインストールされ、ローカルシステムアカウントで実行されるよう構成され、JetStream データディレクトリがセットアップされ、安全な認証トークンが Windows レジストリ内にロックダウンされます。


3. Deploying the Backend API & SPA

バックエンドは、オペレーター接続を管理し、イベントログを処理します。

  1. Stage the backend binaries and React SPA bundle using scripts/build-release.ps1 -Roles backend.
  2. Deploy the service:
    # Elevated PowerShell prompt
    & "dist\backend\deploy-backend.ps1" `
        -NatsToken "your-secure-nats-token" `
        -StaticToken "your-operator-spa-bearer-token" `
        -ForceConfig -Recreate
    
  • -NatsToken: バックエンドをローカルの NATS サーバーに安全に接続します。
  • -StaticToken: オペレーターの CLI/SPA ログインに必要な API ベアラートークンを定義します。

デプロイスクリプトは、KanadeBackend Windows サービスを登録し、適切な ACL を設定して、エンドポイントを検証します。


4. Installing the Agent on Target Endpoints

管理対象のすべてのエンドポイント PC にエージェントをインストールします。

  1. Stage the agent bundle using scripts/build-release.ps1 -Roles agent.
  2. Copy the contents of the dist/agent folder to the target PC.
  3. On the target PC, run the installer:
    # Elevated PowerShell prompt
    & ".\deploy-agent.ps1" -NatsToken "your-secure-nats-token" -ForceConfig -Recreate
    

スクリプトの動作:

  • Places kanade-agent.exe into its destination directory.
  • Secures the configuration and NATS token in the Windows registry path (HKLM:\SOFTWARE\Kanade\agent).
  • Registers and starts the KanadeAgent service.

サービスが起動すると、エージェントはアウトバウンド NATS 接続を確立し、コマンドストリームを購読し、オンラインのハートビートをフリートバックエンドに報告します。

agent 経由のアップデート

agent は万能インストーラーです。対象ホストで動き出してしまえば、他のどのコンポーネントをアップデートするときも operator がホストに直接触る必要はありません — agent が話している backend も、メッセージを運ぶブローカーも、agent 自身も対象です。

この章はコンポーネントごとに 1 ページずつあります:

全コンポーネントで共通の仕組み:

バケット / ストリーム用途
OBJECT_APP_PACKAGES汎用バイナリストレージ (backend、client、NATS サーバーなど)。キーは <name>/<version>
OBJECT_SCRIPTSマニフェストが script_object で参照する PowerShell スクリプト本体。キーは <name>/<version>
OBJECT_AGENT_RELEASESagent バイナリ専用。agent の rollout 専用の watcher / target_version フローを持つので APP_PACKAGES とは別バケットになっています。
agent_config (KV)レイヤード config — global / グループ別 / PC 別。target_version はここに置かれます。
jobs (KV)ジョブカタログ。各エントリは operator が exec できるマニフェストです。

CLI コマンド一覧:

コマンド動作
kanade app publish <name> <version> <file>OBJECT_APP_PACKAGES にアップロード。
kanade script publish <name> <version> <file>OBJECT_SCRIPTS にアップロード。
kanade job create <yaml>jobs KV にジョブマニフェストを upsert。
kanade exec <job-id> --pcs <pc> [--pcs <pc> …]登録済みジョブを PC 群に対して起動。
kanade agent publish <file>agent バイナリをアップロード (バージョンは PE VERSIONINFO から自動抽出)。
kanade agent rollout <version> --pc \| --group \| --global指定スコープの target_version を切り替え。各 agent は self-update watcher 経由でこれを拾います。

kanade-backend のアップデート

backend は管理対象ホスト 1 台 (またはそれ以上) で Windows サービスとして動いています。agent 経由のアップデートとはつまり、そのホスト上で動いている agent がサービスを止め、バイナリを差し替え、再起動するという話 — operator はそのホストに一度もログインしません。

end-to-end フロー

┌── operator host ──────────────────────────────────────────┐
│  1. build kanade-backend.exe                              │
│  2. kanade app publish kanade-backend <v> <exe>           │
│  3. edit deploy-backend.ps1 (set $AgentSource* knobs)     │
│  4. kanade script publish deploy-backend <v> <edited.ps1> │
│  5. kanade job create install-kanade-backend.yaml         │
│  6. kanade exec install-kanade-backend --pcs <host>       │
└────────────────────────────────────────────────────────────┘
                      │
                      ▼
┌── target host (running kanade-agent as LocalSystem) ──────┐
│  • agent receives the Command on commands.pc.<host>       │
│  • fetches deploy-backend.ps1 from OBJECT_SCRIPTS         │
│    sha-verifies it (`script_object` machinery, #214)      │
│  • stages it under                                        │
│    C:\ProgramData\Kanade\agent-scripts\<UUID>\            │
│    kanade-<UUID>.ps1                                      │
│  • runs `powershell -File <launcher>` (PR #230 fix)       │
│  • launcher invokes the user script via `& '...'`         │
│    so [CmdletBinding()] / param() headers parse           │
│  • script downloads kanade-backend.exe from               │
│    OBJECT_APP_PACKAGES (via /api/app-packages/…)          │
│    sha-verifies it (separate hash, on the exe itself)     │
│  • Stop-Service KanadeBackend                             │
│  • copy exe over C:\Program Files\Kanade\…                │
│  • Start-Service KanadeBackend                            │
│  • exit 0 — result published to NATS                      │
└────────────────────────────────────────────────────────────┘

sha チェックが 2 段ある理由は意図的: スクリプト本体のハッシュは agent が実行前に検証 (スクリプトの完全性)、バイナリのハッシュはスクリプトが swap 前に検証 (バイナリの完全性、operator が $AgentSourceSha256 で指定)。

ステップごとの手順

1. kanade-backend をビルド

cargo build --release -p kanade-backend

出力: target/release/kanade-backend.exe

2. バイナリを publish

kanade app publish kanade-backend 0.43.0 target/release/kanade-backend.exe

これでバイナリが OBJECT_APP_PACKAGES/kanade-backend/0.43.0 にアップロードされ、sha-256 digest が表示されます。digest を控えておきましょう — 後でスクリプトに lowercase-hex 形式で書き込みます。

3. scripts/deploy/backend.ps1 を編集

ローカルコピーを作って、先頭の 4 つの $Agent* ノブをセットします:

$AgentSourceUrl       = 'http://kanade-backend.example.com:8080'
$AgentSourceVersion   = '0.43.0'
$AgentSourceSha256    = '<kanade-backend.exe の lowercase hex>'
$AgentSourceAuthToken = '<backend HTTP API 用 bearer>'

スクリプトの他の部分は触らないでください — このノブが「agent モード」(backend からダウンロード) と「手動インストールモード」(ローカルフォルダから 読み込み) を切り替えるトリガになっています。

$AgentSourceSha256Get-FileHash kanade-backend.exe -Algorithm SHA256 の hex 形式の値です。

kanade app publish の出力にある base64url 形式しか手元にない場合は decode します。CLI から出る base64 は URL-safe で padding なしのことがあるので、FromBase64String に通す前に padding を補う必要があります:

$b64 = '<paste the SHA-256= value here, without the SHA-256= prefix>'
$b64 = $b64.Replace('-', '+').Replace('_', '/')
if ($b64.Length % 4) { $b64 += '=' * (4 - $b64.Length % 4) }
[BitConverter]::ToString([Convert]::FromBase64String($b64)).Replace('-', '').ToLowerInvariant()

Python の場合: python -c "import base64; print(base64.urlsafe_b64decode('<b64>' + '=' * (-len('<b64>') % 4)).hex())"

$AgentSourceAuthToken は 2026-05-26 の live test 以降必須です — backend の /api/app-packages/<name>/<ver> エンドポイントは token なしだと HTTP 401 を返します。auth なしの lab 環境のときだけ空のままで OK。

4. 編集したスクリプトを publish

kanade script publish deploy-backend 0.43.0 .\deploy-backend.edited.ps1

アップロード先は OBJECT_SCRIPTS/deploy-backend/0.43.0

5. ジョブを登録 / 更新

リポジトリの configs/jobs/installers/install-kanade-backend.yaml がテンプレートです。version:script_object: をいま publish したバージョンに合わせて編集してから upsert:

id: install-kanade-backend
version: 0.43.0
execute:
  shell: powershell
  script_object: deploy-backend/0.43.0
  timeout: 300s
  run_as: system
require_approval: true
kanade job create jobs\install-kanade-backend.yaml

run_as: system は必須です: Stop-Service / Start-Service / sc.exe はいずれも admin が必要です。本番環境では agent は LocalSystem で動いているので問題ありません。

6. 起動

kanade exec install-kanade-backend --pcs <backend-host>

CLI はすぐに exec_id を返します。実際のインストールは対象ホスト上で非同期に走ります。

7. 確認

backend の results エンドポイントを叩く (もしくは SPA の Activity ビューを見る):

curl -H "Authorization: Bearer <token>" `
  "http://<backend>/api/results?limit=5"

自分の exec_idexit_code: 0 で、stdoutkanade-backend <new-version> で終わっていれば成功です。

ありがちなトラブル

症状原因対処
stderr に [CmdletBinding()] / param() の parse erroragent が 0.42.2 より古い (-Command モードで動いている)まず kanade agent rollout で agent をアップグレード (agent self-update 参照)。
Start-BitsTransfer : HTTP status 401$AgentSourceAuthToken が空だが backend が auth を要求している値をセットする。
Start-BitsTransfer : The transfer encountered an error / job state TransientErrorBITS service not running, or target machine's WinHTTP can't reach $AgentSourceUrlGet-Service BITS; check WinHTTP proxy with netsh winhttp show proxy (BITS uses WinHTTP, not IE/WinINet).
sha256 mismatch — expected=<x> actual=<y>スクリプトの hash が publish されたバイナリと一致しない再 publish するか hash を計算し直す。スクリプトは swap の に abort するので、既存のインストールは無事です。
ジョブは実行されたが kanade-backend が起動してこない対象ホストでのサービス起動失敗 / config の不整合対象ホストの C:\ProgramData\Kanade\log\backend.*.log を読む。agent 経由で kanade logs <pc> で取れる (実装後) か、直接ファイルを引き上げる。

kanade-client のアップデート

Tauri デスクトップクライアントは backend と同じやり方で端末に配布します: バイナリは OBJECT_APP_PACKAGES、スクリプトは OBJECT_SCRIPTS、ジョブは jobs KV。形は backend のアップデート と同じで、スクリプト内容とパッケージ名だけが違います。

backend のアップデートとの違い

項目kanade-backendkanade-client
(再) 起動するサービスKanadeBackend (Windows サービス)なし — クライアントはユーザーが起動する
インストール先%ProgramFiles%\Kanade\kanade-backend.exe%ProgramFiles%\Kanade\kanade-client.exe
リポジトリ内のスクリプトscripts/deploy/backend.ps1configs/jobs/installers/scripts/install-kanade-client.ps1 (マニフェストの script_file パス)
マニフェストの参照方法script_object: deploy-backend/<v>script_file: scripts/install-kanade-client.ps1 (マニフェスト YAML からの相対パス; kanade job create 時に inline 展開)
atomic swap のやり方サービス停止 → コピー → サービス起動<exe>.new にステージ → Move-Item<exe>.old を削除
インベントリへの射影なし (backend は自分自身でバージョンを報告)inventory: ブロックが PC ごとのクライアントバージョンを SPA Inventory ページに出す

両方の形が使えます — script_object (OBJECT_SCRIPTS から hash で参照、agent が必要時に fetch) と script_file (kanade job create 時にスクリプト本体をマニフェストに inline 展開)。client マニフェストは歴史的経緯で script_file、backend マニフェストは Object Store パスをテストするために script_object に書き換えられました。

ステップごとの手順

1. kanade-client をビルド

cargo build --release -p kanade-client

出力: target/release/kanade-client.exe

2. バイナリを publish

kanade app publish kanade-client 0.42.0 target/release/kanade-client.exe

3. configs/jobs/installers/scripts/install-kanade-client.ps1 を編集

先頭の 3 つのノブをセット:

$BackendBase    = 'http://kanade-backend.example.com:8080'
$Version        = '0.42.0'
$ExpectedSha256 = '<kanade-client.exe の lowercase hex>'

backend auth が有効なら $ClientSourceAuthToken を backend の bearer にセットしてください — agent が /api/* に使うのと同じトークンです。/api/app-packages/kanade-client/<v> ルートが認証なしの dev / smoke-test 環境では空のままで OK。scripts/deploy/backend.ps1$AgentSourceAuthToken ノブと同じ形です。

4. ジョブを登録 / 更新

configs/jobs/installers/install-kanade-client.yaml:

id: install-kanade-client
version: 0.42.0
execute:
  shell: powershell
  script_file: scripts/install-kanade-client.ps1   # `job create` 時に inline 展開 (マニフェスト YAML からの相対パス)
  timeout: 180s
  run_as: system

require_approval: true

inventory:
  display:
    - { field: version, label: Version }
    - { field: path,    label: Install path }
  summary:
    - { field: version, label: Client version }
kanade job create jobs\install-kanade-client.yaml

inventory: ブロックは projector に「スクリプトの stdout は単一の JSON blob で、version / path フィールドが SPA の Inventory ページに反映される」と伝えます。operator は fleet 全体のテーブルから取り残し端末を見つけられ、ssh は不要です。

5. 起動

kanade exec install-kanade-client --pcs <host> [--pcs <host> …]

もしくはグループ単位で:

kanade exec install-kanade-client --groups office

6. SPA で確認

SPA の Inventory ページを開く (もしくは /api/inventory?app=kanade-client を叩く) と、対象ホストが新しいバージョンを報告しているはずです。

NATS サーバーのアップデート

管理対象ホスト上のブローカーをアップデートするのは一番面白いケースです。なぜなら agent は ブローカー越しにブローカーと話す から — NATS を止めると ジョブの途中で agent との接続が切れます。これに対しては 2 つの仕組みが組み合わさって対処しています:

  1. 再接続。 agent の NATS クライアントはブローカー再起動時に自動再接続します。人の介入は不要。
  2. outbox。 ブローカーが落ちている間に発生したジョブ結果は %ProgramData%\Kanade\outbox\ に貯められ、接続が戻り次第再送されます。新しい NATS サーバーが立ち上がるとすぐに result row が backend に届きます。

したがってフローは backend のアップデート と同じ — スクリプトはサービスを止めてバイナリを差し替え再起動し、agent はブローカーの空白期間を透過的にやり過ごします。

NATS アップデート固有の注意点

懸念実際
result row はロストする?いいえ — outbox がブローカー停止中を跨いで保持し、再接続時に drain します。
SPA からアップデートできる?はい、他のジョブと同じです — kanade exec install-kanade-nats --pcs <broker-host>
NATS が再起動してこなかったら?result は outbox にずっと残ります。operator はブローカーホストの outbox/ を復帰失敗の早期サインとして監視するべき。
新しい NATS バージョンに互換性がなかったら (JetStream のアップグレードなど)?まず canary 1 台に rollout (--pcs <one-broker>)、outbox と backend の健全性を見てから fleet 全体に展開。SPA クエリには 5 分の cache TTL があるので canary の状態は数分以内に反映されます。

手動インストール (ブートストラップ)

初回インストール (ブローカーホストにまだ agent がない状態) では直接ワークフローを使います:

.\scripts\build-release.ps1 -Roles nats       # fetches nats-server.exe
                                              # from github.com/nats-io/nats-server/releases
.\scripts\deploy\nats.ps1 -NatsToken '<token>'

これで nats-server.exe%ProgramFiles%\Kanade\ に、nats-server.conf%ProgramData%\Kanade\config\ にインストール (bearer token を平文で保存するので ACL を SYSTEM + Administrators のみに絞ります)、KanadeNats Windows サービスを登録、TCP 4222 (broker) と 8222 (monitoring HTTP) を開放、サービスを起動します。

agent 経由のアップデート (定常運用)

ステータス: template のみ。scripts/deploy/nats.ps1 はまだ $AgentSource* ノブを持っていません — agent モードは backlog 行きです。下記はノブが入った後の想定形です。

1. nats-server.exe をビルド or 取得

どちらか:

.\scripts\build-release.ps1 -Roles nats   # fetches the binary

…もしくは github.com/nats-io/nats-server/releases から直接ダウンロード。

2. バイナリを publish

kanade app publish nats-server 2.10.20 .\nats-server.exe

3. deploy-nats.ps1 を編集

agent モードノブが入ったあとは、パターンは deploy/backend.ps1 と同じ:

$AgentSourceUrl       = 'http://kanade-backend.example.com:8080'
$AgentSourceVersion   = '2.10.20'
$AgentSourceSha256    = '<nats-server.exe の lowercase hex>'
$AgentSourceAuthToken = '<backend HTTP API 用 bearer>'

4. publish + 登録 + exec

kanade script publish deploy-nats 2.10.20 .\deploy-nats.edited.ps1
kanade job create jobs\install-kanade-nats.yaml
kanade exec install-kanade-nats --pcs <broker-host>

ジョブマニフェストはこんな形になります:

id: install-kanade-nats
version: 2.10.20
execute:
  shell: powershell
  script_object: deploy-nats/2.10.20
  timeout: 300s
  run_as: system
require_approval: true

5. 確認

ブローカーが復帰すると outbox が drain され、/api/results に result row が出てきます。新しい NATS バージョンはブローカーの monitoring エンドポイントで確認:

curl http://<broker>:8222/varz | python -m json.tool | rg version

なぜ独立した「broker update」機構が要らないのか

初期の設計では「ブローカー越しにブローカーを更新する鶏卵問題」を避けるために専用のブートストラップチャネル (agent が broker update 専用に使う並列 NATS 接続) を検討していました。outbox + 再接続のペアによってこれは不要に: 結果は「失われる」のではなく「遅延するだけ」。トランスポートはひとつ、メンタルモデルもひとつで済みます。

kanade-agent 自身のアップデート

agent の self-update は唯一 OBJECT_APP_PACKAGES + script_object ジョブを 使わない コンポーネントです。agent は ssh なしで現在実行中の自分自身のバイナリを差し替える必要があり、汎用 install ジョブよりタイトなループのため専用の仕組みを持っています。

仕組み

バケット / キー用途
OBJECT_AGENT_RELEASESagent バイナリ。キーは <version>。rollout watcher が agent アップデートだけに反応するように、OBJECT_APP_PACKAGES とは別バケット。
agent_config.<scope>.target_version各スコープ (global / グループ / pc) があるべきバージョン。agent の self_update ループがこれを watch しています。

フロー:

1. agent.self_update watches agent_config for target_version
2. If target_version != my agent_version:
   a. Pull `OBJECT_AGENT_RELEASES/<target_version>` to <exe>.new
   b. Sha-verify against the bucket's recorded digest
   c. Atomic swap: <exe> ← <exe>.new (via SCM stop/start)
   d. New binary boots, watcher arms again, loop closes

rollout watcher は cold broker (ホスト再起動後に agent と broker が同時に立ち上がる、など) に耐えなければなりません。#226 以前は最初の get_object_store 呼び出しで Err(_) => return; してしまうと watcher が恒久的に死んでいて、その起動セッション中は agent が二度と self-update しませんでした。#226 以降は watcher が backoff で再試行し、broker に到達できるまであきらめません。

ステップごとの手順

1. agent をビルド

cargo build --release -p kanade-agent

出力: target/release/kanade-agent.exe

2. publish

kanade agent publish target/release/kanade-agent.exe

CLI は PE VERSIONINFO リソースからバージョンを自動抽出します — --version フラグ不要、ラベルとバイナリの不一致もあり得ません。

3. roll out

スコープを選びます。canary 1 台から:

kanade agent rollout 0.42.2 --pcs canary-01

ping で確認:

kanade ping canary-01     # agent_version should flip to 0.42.2
                          # within a few seconds

問題なければ範囲を広げる:

kanade agent rollout 0.42.2 --groups office --jitter 5m
# or fleet-wide
kanade agent rollout 0.42.2 --global --jitter 30m

--jitter は実際の swap タイミングをある幅で分散させ、大きな fan-out 時に全ホストの OS サービスマネージャを同時に叩かないようにします。100 台以上の fleet では推奨。

4. 確認

kanade agent current
# → target_version = 0.42.2 (global)

あとは SPA の Agents ページ (もしくは /api/agents) で fleet 全体をスポットチェック: agent_version 列は jitter + 約 30 秒の heartbeat 間隔以内に新バージョンに収束するはず。

ありがちなトラブル

症状原因対処
kanade agent rollout が "version not in OBJECT_AGENT_RELEASES" と言うtypo もしくはスコープ違いkanade agent currentkanade jetstream object list agent_releases で再確認。
数分経っても kanade ping <host> が古いバージョンを返すagent が self-update しなかった — watcher が死んでいる (#226 以前の agent) か、ホストが broker に到達できない対象ホストの %ProgramData%\Kanade\log\agent.*.log をチェック。self_update が無言なら (「checking target_version」ログがない)、agent が古すぎる; deploy-agent.ps1 で手動ブートストラップ。
agent が flap する: 起動するも exit_code: 1 ですぐ落ちるこのホストでは新バイナリが起動できない (config の不整合、依存欠落など)。SCM の failure-actions により再起動が試みられるが再びクラッシュする — Event Viewer に Service Control Manager のエラーが連続して記録されるロールバック: kanade agent rollout <prev-version> --pcs <host>。次の watcher tick でホストは元のバージョンに戻ります。

なぜ別のバケット / スコープか?

OBJECT_APP_PACKAGES<name>/<version> をキーにした汎用 blob ストアです。agent rollout パターンに必要なのは:

  • agent の変更だけに反応する watcher (たくさんの名前が入ったバケットを poll するのではなく、特定の 1 つの KV キーを安価に watch)。
  • 「既知の全バージョン」ではなくスコープごとの「現在の target」セマンティクス — agent_config.<scope>.target_version こそが「自分は何を動かすべきか」の答えで、agent 側で列挙する必要がない。
  • operator 向け UX (kanade agent publish / rollout) が kanade app publish とは別サブコマンドツリーに分けるに足るくらい違う。

というわけで agent は OBJECT_AGENT_RELEASES + レイヤード config KV を、他のコンポーネントは OBJECT_APP_PACKAGES + アプリ別ジョブを共有します。

kanade をホストから取り除く (undeploy)

本番でのロールバック経路。rollout で何かが壊れた、ホストを廃止する、再インストール用にまっさらな状態に戻したい — そんなときホストから kanade を剥がすために、deploy と対になる undeploy スクリプトをコンポーネントごとに 1 本ずつ用意しています。

コンポーネントDeployUndeploy
Agentscripts/deploy/agent.ps1scripts/undeploy/agent.ps1
Backendscripts/deploy/backend.ps1scripts/undeploy/backend.ps1
NATS serverscripts/deploy/nats.ps1scripts/undeploy/nats.ps1
Client (Tauri)configs/jobs/installers/scripts/install-kanade-client.ps1 (agent-driven)scripts/undeploy/client.ps1

All four are admin-only and idempotent — safe to re-run after a partial uninstall, safe to run when the component is already gone (each step logs "not present, skipping" and moves on).

デフォルトの姿勢: 安全側

フラグなしで実行するとスクリプトは:

  • Windows サービスを停止します。
  • SCM からサービスを unregister します (エントリが実際に消えるまで待つので、後続の再 deploy が pending な削除と race しません)。
  • %ProgramFiles%\Kanade\ からインストール済みバイナリを削除します。中途半端な <exe>.new / <exe>.old の swap 残骸もまとめて削除。
  • deploy スクリプトが作成した inbound のファイアウォールルールを削除します (-KeepFirewall で skip 可 — 外部の WAF / グループポリシーがルールを管理している場合に有用)。
  • %ProgramData%\Kanade\ 配下 (config、log、JetStream データ、SQLite DB、…) は 残します。フォレンジック / rollback / 再 deploy が state を失わずに進められるように。
  • HKLM:\SOFTWARE\kanade\<role>\* のレジストリ secret も 残します

That's enough for the common case: "this host's kanade is misbehaving, get it off without destroying state".

-Purge: 破壊的クリーンアップ

追加で:

  • そのコンポーネント固有の %ProgramData%\Kanade\ 配下エントリを削除します。重要なのは そのコンポーネント自身のファイルだけ — agent / backend / NATS は同じ root を共有しているので、各スクリプトは他のコンポーネントのファイルには触れません。
  • 対応する HKLM:\SOFTWARE\kanade\<role>\* キーを削除します (-KeepSecrets を併せて渡すとスキップ — 複数コンポーネントで同じ bearer を共有しているときに有用)。
コンポーネント-Purge が削除するもの
Agentconfig\agent.tomllogs\agent.*.logoutbox\HKLM:\SOFTWARE\kanade\agent\
Backendconfig\backend.tomldata\*.db* (SQLite — 過去の results / inventory が消える)、logs\backend.*.logHKLM:\SOFTWARE\kanade\backend\
NATSconfig\nats-server.confnats\ (JetStream — KV / Object Store / streams すべて消える)、logs\nats*.log
Client追加なし (per-user な state はまだ存在しない)

⚠️ 危険なのは undeploy-nats.ps1 -Purgeundeploy-backend.ps1 -Purge。前者は fleet 全体の JetStream state (agent_releases、app_packages、scripts、jobs、agent_config、results stream) を消し、後者は projector の過去の SQLite を消します。どちらも out-of-band バックアップ無しではリカバリ不能。スクリプトは実行前に目立つバナーを出します。

ロールバックの定石

canary 1 台で rollout が壊れたとき

# On the canary, as Admin:
.\scripts\undeploy\agent.ps1            # safe default
# kanade is now off the host. Re-deploy when ready:
.\scripts\deploy\agent.ps1 -SourceDir C:\path\to\prev-version

ホストを恒久的に廃止する

.\scripts\undeploy\agent.ps1 -Purge

dev box を再インストール用にまっさらにする

.\scripts\undeploy\agent.ps1 -Purge
.\scripts\undeploy\backend.ps1 -Purge   # ⚠️ SQLite gone
.\scripts\undeploy\nats.ps1 -Purge      # ⚠️ JetStream gone
.\scripts\undeploy\client.ps1
# Now nothing about kanade exists on the box.

state は触らず壊れたサービスだけ作り直す

.\scripts\undeploy\backend.ps1          # safe default: SQLite intact
.\scripts\deploy\backend.ps1 -Recreate  # fresh service registration, same data

undeploy がやらないこと

  • It doesn't notify the rest of the fleet that this host has gone away — the backend will keep listing it under "agents" until its heartbeat ages out (/api/agents staleness threshold). If you want it removed from the SPA immediately, delete the row via the backend API after undeploy.
  • It doesn't roll back the deployed binary to a previous version. "Roll back" in this script's vocabulary means "remove entirely"; if you want to swap to an older version, re-run the matching deploy-*.ps1 against a folder containing the older binary.
  • agent を取り除いても NATS 側の state には触れません — agent の target_version エントリは agent_config.pcs.<pc> 配下の KV に残ります。必要なら server 側で kanade jetstream kv del agent_config pcs.<pc>.target_version で掃除してください。

agent 向けスクリプトを書く

agent が実行する PowerShell スクリプトは ほぼ 通常の .ps1 ファイルです。このページは、スクリプトのソースを見るだけでは分からない罠をまとめます。

agent はスクリプトをディスクに staging してから -File で実行する

PR #230 (agent version 0.42.0+) 以降、agent は次の動作をします:

  1. スクリプト本体を temp の .ps1 に書き出します。Windows なら %ProgramData%\Kanade\agent-scripts\<UUID>\kanade-<UUID>.ps1、それ以外 (dev のみ) なら $TMPDIR/kanade-agent-<UUID>/kanade-<UUID>.ps1
  2. その隣に launcher .ps1 を書き、UTF-8 コンソールエンコーディングを設定してから & '<your-script>' @args でユーザースクリプトを呼びます。
  3. powershell -NoProfile -NonInteractive -ExecutionPolicy Bypass -File <launcher> を spawn します。

結果として、あなたのスクリプトでは:

  • 先頭に [CmdletBinding()]param(...)書けます。launcher の call-operator 境界が独自スコープを生み、その中ではヘッダーが有効です。
  • $PSCommandPath が operator のソースパスと一致することを 期待しないでください — staged 後の temp ファイルパスになります。
  • $PSScriptRoot書き込まないでください (次節参照)。

Pre-0.42.0 agents used powershell -Command "<body>", which parses the body as a command-line expression and rejects [CmdletBinding()] as a syntax error. If you see "Unexpected token '[CmdletBinding()]'" in stderr, the host's agent is too old — upgrade it (see agent self-update).

run_as: user のとき $PSScriptRoot は読み取り専用

run_as: user (または system_gui) のとき、子プロセスはログオン中のユーザーとして動きます — staged ファイルを書いた LocalSystem の agent ではありません。staging ディレクトリは %ProgramData% から ACL を継承していて、Users には Read & Execute は許可されるが Modify は許可されません

つまり:

# OK from any run_as
Get-ChildItem $PSScriptRoot              # list contents
Get-Content   $PSScriptRoot\anything     # read

# NG from run_as: user (access denied)
New-Item    -Path $PSScriptRoot\out.txt
Set-Content -Path $PSScriptRoot\log.log

代わりに $env:TEMP$env:LOCALAPPDATA、ユーザープロファイル配下の絶対パスのいずれかに書いてください。run_as: system (SYSTEM が自分の staged dir に書ける) であっても、スクリプト終了時にディレクトリは掃除されるので、隣接ファイル書き込みはいずれにせよ壊れやすいです。

実行 identity 一覧

run_as: (マニフェスト)子プロセスの identity$PSScriptRoot を読める$PSScriptRoot に書けるadmin 権限あり
system (デフォルト)LocalSystem✓ (ただし無意味、GC される)はい
userログオン中のユーザー✗ access deniedいいえ
system_guiLocalSystem (ユーザーセッション内)✓ (ただし無意味、GC される)はい

system_gui is the "PsExec -i -s" pattern — admin privilege but visible in the user's desktop session (useful for GUI tools that need both elevation and an interactive window).

stdout vs Write-Host

backend の result projector はスクリプト出力として stdout を読みます。マニフェストに inventory: ブロックがあると、stdout は単一の JSON blob としてパースされます。

進捗メッセージには Write-Host を使ってください — host ストリームに行き、stdout には行かないので JSON パースを汚しません。

Write-Host "Downloading..."         # → host stream (logged but ignored by projector)
Write-Output ($obj | ConvertTo-Json) # → stdout (parsed)

メッセージ出力に Write-Output は使わないこと — stdout に期待される JSON 以外が混ざると inventory パースが失敗します。

デフォルトで UTF-8

launcher はスクリプト起動前に [Console]::OutputEncoding = UTF-8$OutputEncoding = UTF-8 を設定するので、ホストのシステムコードページに関係なくあなたの stdout / stderr は UTF-8 になります。日本語 / DE / KR / CN を含む operator スクリプトも、ホスト個別の workaround なしに SPA Activity ビューで正しく表示されます。

明示的に OEM / CP932 / Shift-JIS 出力が必要なら ($OutputEncoding を無視する legacy CLI を呼ぶケースなど)、launcher の prelude が走ったあとにスクリプト内で自分で設定してください — あなたの代入が優先されます。

ネイティブコマンドの exit code

スクリプトが成功した native コマンドで終わると全体の exit は 0 — これは PowerShell のデフォルトです。native コマンドが失敗 ($LASTEXITCODE -ne 0) してハンドリングしないと、PowerShell は依然として 0 で終了します — $ErrorActionPreference = 'Stop'救ってくれません

Windows PowerShell 5.1 (Windows エンドポイントのデフォルト、agent の powershell.exe が解決する先) は $ErrorActionPreference に関わらず native コマンドの非ゼロ exit を non-terminating として扱います。PowerShell 7.3+ で $PSNativeCommandUseErrorActionPreference = $true が追加されてこれを terminating にできますが、デプロイターゲットでは使えません。必ず $LASTEXITCODE を明示的にチェックしてください。

agent も $LASTEXITCODE を自動 propagate しません — そうしてしまうと、スクリプトが native エラーを正しく処理した場合でも非ゼロで終わってしまうからです。特定の native 呼び出しの exit code をスクリプトの exit に反映させたい場合は自分で propagate してください:

& git pull
if ($LASTEXITCODE -ne 0) { throw "git pull failed with exit code $LASTEXITCODE" }
# or, if you want the exact native code propagated:
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }

通常は throw のほうが望ましい — クリーンな PowerShell エラーレコードを生成し (trap { … break } クリーンアップパターンが捕まえられる) かつ非ゼロで終わるからです。exit $LASTEXITCODE は呼び出し側が正確な exit code を気にする場合に向きます。

タイムアウト

マニフェストの timeout: は agent によって適用されます。発火すると agent は PowerShell プロセスに child.kill() を呼びます — graceful な shutdown も trap も finally もありません。それを前提に設計してください:

  • スクリプトが timeout * 0.6 で終わるように実行時間を見積もり、余裕を残す。
  • 明示的解放が要るリソース (staging dir、lock ファイル) のクリーンアップには trap { ... ; break } を使う — trap は terminating エラーで発火し、agent の kill では発火しません。timeout ケースには頼らないこと。
  • If you need cooperative cancellation, poll a sentinel file or a registry value and exit early. The agent has no way to send the script a graceful "wrap up" signal.

実行中ジョブの kill

kanade kill <exec_id> は agent が購読する kill メッセージを publish します。受信すると agent は child.kill() を呼びます — timeout 経路と同じ hard-kill。operator にはただちに Killed マークの result row が届き、終了前に agent がキャプチャできた stdout / stderr が付きます。

開発者ワークフローとコントリビューション

このドキュメントでは、kanade コードベースで作業するコントリビューター向けの標準的な開発ワークフロー、lint/テストの要件、および VCS ブランチのガイドラインについて説明します。


1. クオリティゲート (Pre-Push & CI)

プッシュや PR の送信を行う前に、ローカルのテストスイートがすべてグリーンである必要があります。これは GitHub Actions で実行される自動チェックと同じものです。

# Run formatting check, clippy checks, target tests, and cargo lock checks
cargo make check
  • FMT & Clippy: 私たちは厳格なゼロワーニングポリシーを維持しています。強力な設計上の正当な理由がない限り、#[allow(clippy::...)] を散布しないでください。
  • TDD (テスト駆動開発): Kent Beck の TDD 手法に従ってください。最初に失敗するテストを書いて「何を」行うかを定義し、次にそれを満たすコードを実装します。

2. renri によるワークツリー管理

隔離された機能開発のために、私たちは renri を使用して軽量なリポジトリワークツリーを管理します。これにより、ステージの汚染を防ぎ、メインチェックアウトをクリーンに保ち、瞬時にタスクを切り替えることができます。

なぜ renri なのか?

Git と Jujutsu (jj) がコロケーションされた環境では、ワークツリーを手動で管理するのは複雑になります。renri は、VCS 固有のワークツリー作成(設定されている場合は jj を優先)とクリーンアップを自動的にラッピングすることで、これを簡素化します。

よく使うコマンド

# Create an isolated worktree (uses Jujutsu by default if present)
renri add feat/your-awesome-feature

# Force a Git-native worktree (bypassing jj)
renri --vcs git add feat/your-awesome-feature

# Clean up and delete a worktree after merging
renri remove feat/your-awesome-feature

# Garbage-collect and prune stale or broken worktrees
renri prune

注意: ワークツリー作成時に自動的に cargo-make の on-add フックが呼び出され、リモートの参照を取得して APM 設定を直ちにセットアップします。


3. コロケーションされた Jujutsu (jj) & Git ワークフロー

開発環境は、Git と Jujutsu がコロケーションされるよう設定されています。ローカルのバージョン管理には、安全で競合のないコミットモデルを持つ jj を好んで使用します。

ガイドライン

  • main への直接プッシュ禁止: すべての変更は Pull Request 経由でマージされる必要があります。
  • ブランチ/ブックマークの命名規則:
    • feat/... は新機能用。
    • fix/... はバグ修正用。
    • chore/... はインフラ、依存関係の更新、またはリリース用。
  • コミットメッセージ: コミットメッセージ、PR タイトル、本文は英語で記述してください。
  • バージョン更新: リリースのバージョン更新は、main への PR と自動タグ付けパイプラインを介してのみ管理されます。手動で git tag を実行しないでください。

4. ドキュメントポリシー

ドキュメントは、コードの変更と常に完全に同期している必要があります。機能を追加または変更した場合は常に、以下を実行してください:

  • コード内のコメントや docstring を更新し、「なぜ」そのようにしたのかを説明します(「どのように」やっているかを単に再記述するコメントは避けてください)。
  • 関連する book ページ(book/src/ 配下に英語で記述)を更新します。
  • 翻訳テンプレートジェネレーターを実行して、ローカライズカタログ(ポファイル)を同期します。

仕様 (旧 single-page)

フルのプロトコル / on-wire 仕様はまだ book に取り込まれていません。オーソリティはリポジトリの single-file 版です:

docs/SPEC.md on GitHub

このセクション配下に章分割するのは、operator / 開発者ガイドが落ち着いてからの follow-up とします。

設定リファレンス

kanade サービスは、TOML ファイル、環境変数、またはレジストリパスから読み込まれる構造化された設定に依存しています。


1. エージェント設定

エージェントは KANADE_AGENT_CONFIG 環境変数を介して設定を検索し、存在しない場合はネイティブパスにフォールバックします。

開発用設定 (configs/agent.dev.toml)

# 開発用設定スキーマ
[agent]
id = "dev-pc"
nats_url = "nats://localhost:4223"
data_dir = "target/dev-data/agent"

[log]
level = "debug"
file = "target/dev-data/agent/logs/agent.log"

設定パラメータ

フィールド説明環境変数による上書き
agent.idStringユニークなハードウェア識別子 (pc_id)。KANADE_DEV_AGENT_ID (テンプレート化)
agent.nats_urlStringNATS ブローカー of ネットワークアドレス。KANADE_NATS_URL
agent.data_dirPath送信トレイのスクリプト、状態データベース、およびローカルの補完データをキャッシュするルートパス。KANADE_AGENT_DATA_DIR
log.levelStringログ出力レベルの冗長度 (error, warn, info, debug, trace)。RUST_LOG
log.filePathローリングログの書き出し先ファイルパス。-

2. バックエンド設定

バックエンドの調整レイヤーは KANADE_BACKEND_CONFIG で指定されたファイルから設定を取得し、指定がない場合はデフォルトの構造体を登録します。

開発用設定 (configs/backend.dev.toml)

[backend]
listen_addr = "127.0.0.1:8081"
nats_url = "nats://localhost:4223"
database_url = "sqlite://target/dev-data/backend/state.db"

[auth]
# 認証設定

設定パラメータ

フィールド説明環境変数による上書き
backend.listen_addrStringHTTP/WebSocket トラフィック用のネットワークバインド文字列。KANADE_BIND_ADDR
backend.nats_urlString対象とする NATS ブローカーの URL。KANADE_NATS_URL
backend.database_urlStringSQLite データベースへの接続文字列。DATABASE_URL
auth.disableBooleanオペレーターのトークン検証を無効にするには true を設定します (開発環境でのみ有効)。KANADE_AUTH_DISABLE

3. Windows レジストリ統合

本番環境では、セキュリティに敏感なトークン(NATS クライアントトークンや管理用 API ベアラートークンなど)は、プレーンテキストファイルではなく、保護された Windows レジストリに保存されます。

キーパス

  • エージェント設定: HKLM:\SOFTWARE\Kanade\agent
  • バックエンド設定: HKLM:\SOFTWARE\Kanade\backend

これらのレジストリパスはローカルの ACL 設定で保護されており、SYSTEM および指定されたオペレーターにのみ読み取り権限が厳密に制限されます。