@camoneart/maestro
Version:
A CLI tool that conducts Git worktrees like an orchestra and accelerates parallel development with Claude Code
551 lines (421 loc) • 30 kB
Markdown
# Maestro
[](https://nodejs.org/)
[](https://www.npmjs.com/package/@camoneart/maestro)
[](https://opensource.org/licenses/MIT)
**[English](/README.md)** | **日本語**

**Git worktreeを "オーケストラ" のように指揮し、Claude Codeとの並列開発を加速させるCLIツール。**
<br />
https://github.com/user-attachments/assets/c8662cc2-733e-4c77-9d3d-3738983731a4
## 目次
- [概要](#概要)
- [主な特徴](#主な特徴)
- [インストール](#インストール)
- [アップデート](#アップデート)
- [要件](#要件)
- [クイックスタート](#クイックスタート)
- [コマンドリファレンス](#コマンドリファレンス)
- [高度な機能](#高度な機能)
- [設定](#設定)
- [トラブルシューティング](#トラブルシューティング)
- [貢献](#貢献)
- [ライセンス](#ライセンス)
## 概要
Maestroは、Git worktreeをより直感的に管理できるCLIツールです。複数のブランチで並行作業を行う際に、ディレクトリを切り替えることなく、各ブランチを独立した「オーケストラメンバー」として扱うことができます。
### なぜ Maestro?
| 課題 | Maestro のアプローチ | 得られるメリット |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------ |
| **並列開発の非効率**<br/>ブランチ切り替え・stash・コンテキストスイッチが多発 | **Worktree を自動管理**<br/>各機能を独立したディレクトリで同時開発 | ブランチ移動ゼロでマルチタスクが快適 |
| **タスク管理が煩雑**<br/>複数機能の状態把握が難しい | **CLI 一覧 & ステータス**<br/>演奏者(worktree)の状態を可視化 | 迷わず現在地と進捗を把握 |
| **レビュー・マージ作業の負荷** | **Claude Code 連携**<br/>AI による差分レビューと自動 PR フロー | レビュー時間を大幅短縮 |
## 特徴
| 機能 | 説明 |
| ----------------------- | ---------------------------------- |
| 🎼 **オーケストラUI** | Worktree を演奏者として直感操作 |
| 🤖 **Claude AI 連携** | AI による差分レビュー & コード提案 |
| 🔗 **GitHub 連携** | Issue / PR から安全なワークツリー生成・リッチなメタデータ保存 |
| 🎯 **tmux / fzf** | キーボードだけで高速セッション切替 |
| 📊 **ステータス** | リアルタイムの worktree 状態監視 |
| 🔄 **自動同期** | 変更をリアルタイムで全演奏者へ反映 |
| 📸 **スナップショット** | 任意の状態を保存・ワンクリック復元 |
| 🏥 **ヘルスチェック** | 孤立ブランチや競合を検出・自動修復 |
| 🛡️ **自動ロールバック** | 失敗時に孤立ワークツリーを自動退場 |
## インストール
### Homebrew を使用 (推奨)
```bash
brew install camoneart/tap/maestro
```
※ Homebrew でインストールすると、zsh / fish / Bash すべての補完スクリプトが自動で配置されます。<br>
※ Bash で利用する場合は `brew install bash-completion@2` が必要です。詳細は [シェル補完](#シェル補完) セクションを参照してください。
### npm を使用
```bash
npm install -g @camoneart/maestro
```
### pnpm を使用
```bash
# pnpm が入っていない場合は最初に: npm install -g pnpm
pnpm add -g @camoneart/maestro
```
## アップデート
### Homebrew を使用
```bash
brew upgrade camoneart/tap/maestro
```
### npm を使用
```bash
npm update -g @camoneart/maestro
```
### pnpm を使用
```bash
pnpm update -g @camoneart/maestro
```
## 要件
| 要件 | バージョン | 用途 | インストールコマンド |
|------|-----------|------|--------------------|
| **Node.js** | >=20.0.0 | JavaScript ランタイム | [nodejs.org](https://nodejs.org/) |
| **Git** | >=2.22 | Worktree サポート | `brew install git` |
| **tmux** (オプション) | Any | セッション管理 | `brew install tmux` |
| **fzf** (オプション) | Any | ファジーファインディング | `brew install fzf` |
| **GitHub CLI** (オプション) | Any | GitHub 連携 | `brew install gh` |
## クイックスタート
```bash
# 1. インストール ※Homebrew 例
brew install camoneart/tap/maestro
# 2. Git プロジェクトに移動
cd ~/path/to/your-repo
# 2.5. プロジェクトで maestro を初期化(新機能!)
mst init # 対話的セットアップ
# または: mst init --yes # デフォルト設定で素早くセットアップ
# 3. 新しい worktree (演奏者) を作成
mst create feature/awesome-feature # まず作成だけ
# 4. その演奏者のシェルに入る
mst shell feature/awesome-feature # シェルへ入室
# ── ワンライナー (tmux + Claude) ──
# 作成と同時に tmux セッションを作成してアタッチを確認 & Claude Code ワークスペースファイルを設定
mst create feature/awesome-feature --tmux --claude-md
```
#### ポイント
- `mst shell <ブランチ名>` でいつでも演奏者に入れます(省略すると fzf で選択)。
- `--tmux` を付けると専用 tmux セッションをブランチ名タイトル付きで作成してアタッチを確認し(非TTY環境では自動アタッチ)、`--claude-md` を併用すると Claude Code ワークスペースファイルを設定します。
- `--tmux-h`/`--tmux-v` は現在の tmux ペインを水平/垂直分割し、新しいペインに自動フォーカスして即座に開発開始できます。
- `--tmux-h-panes <数>`/`--tmux-v-panes <数>` は指定数の水平/垂直ペインを作成します。
- `--tmux-layout <種類>` は特定の tmux レイアウト(even-horizontal、even-vertical、main-horizontal、main-vertical、tiled)を適用します。
### 基本的な使用例
| 目的 | コマンド例 |
| --------------------------------------- | ---------------------------------------------------------------------------- |
| **並列開発** 新機能とバグ修正を同時進行 | `mst create feature/auth --tmux --claude-md`<br>`mst create bugfix/login-issue` |
| **状態確認** 演奏者一覧を表示 | `mst list` |
| **GitHub メタデータ付き一覧** | `mst list --metadata` |
| **高速切替** tmux セッションへ | `mst tmux` |
| **GitHub Issue から作成** | `mst create 123` |
| **GitHub PR から作成** | `mst github checkout 456` |
| **GitHub PR から作成(tmux付き)** | `mst github checkout 456 --tmux-h` |
| **GitHub issues/PRs一覧表示** | `mst github list` |
| **Push with PR** | `mst push --pr` |
| **Push with draft PR** | `mst push --draft-pr` |
| **自動レビュー & マージ** | `mst review --auto-flow` |
## コマンドリファレンス
詳細は [コマンドリファレンス](./docs/COMMANDS.md) を参照してください。
### 主要コマンド
| コマンド | 説明 | ショート例 |
| ----------- | -------------------------- | ------------------------------ |
| `init` | プロジェクト設定を初期化 | `mst init --yes` |
| `create` | 新しい worktree を作成 | `mst create feature/login` |
| `list` | worktree を一覧表示 | `mst list` |
| `delete` | 演奏者の退場とスマートなtmuxセッション処理 | `mst delete feature/old --keep-session` |
| `tmux` | tmux セッションで開く | `mst tmux` |
| `sync` | ファイルをリアルタイム同期 | `mst sync --auto` |
| `push` | Push してPR作成 | `mst push --pr` |
| `github` | Issue / PR 連携 | `mst github checkout 123` |
| `health` | worktree 健全性チェック | `mst health --fix` |
| `where` | 現在位置確認 | `mst where` |
すべてのサブコマンドと詳細オプションは [コマンドリファレンス](./docs/COMMANDS.md) を参照してください。
#### ワンラインチートシート
```bash
# 代表的な操作
mst create feature/my-ui --tmux --claude-md # 作成 + AI + tmux
mst create feature/api --tmux-h-panes 3 # 作成 + 3つの水平ペイン
mst list # 一覧
mst tmux # fzf で切替
mst push --pr # push with PR
mst review --auto-flow # 自動レビュー〜マージ
```
## 高度な機能
Maestro が提供する “もう一歩進んだ” 機能を一覧で把握できます。<br>
各コマンドは **1 行** で実行でき、煩雑な作業をまるごと自動化します。
| 機能 | コマンド例 | やってくれること |
| ---------------------------- | -------------------------------------------------------------- | -------------------------------------------------------------------------------- |
| **自動レビュー & マージ 🚀** | `mst review --auto-flow` | fetch → rebase → AI レビュー → Conventional Commit → PR 作成をワンコマンドで実行 |
| **GitHub連携 🔗** | `mst github list` <br>`mst github checkout 123 --tmux-h` <br>`mst list --metadata` | GitHub issue/PR一覧表示・安全なチェックアウト・包括的メタデータ保存・tmux連携、リポジトリワークフロー自動化 |
| **スナップショット 📸** | `mst snapshot -m "前の状態"` <br>`mst snapshot --restore <id>` | 任意時点の状態を保存し、いつでも復元 |
| **健全性チェック 🏥** | `mst health` <br>`mst health --fix` | stale / orphaned / conflict などを検出し、自動修復 |
さらに詳しいオプションは `mst <command> --help` で確認できます。
## 設定
### 📁 プロジェクト設定 `.maestro.json`
Maestro は **リポジトリ直下の `.maestro.json`** を読み取り、動作をカスタマイズできます。<br>
よく使うキーを以下の表にまとめ、完全なサンプルは表に続くコードブロックで確認できます。
### ⚙️ 設定管理
Maestroはドット記法を使って設定を管理するコマンドを提供します:
```bash
# 設定値を取得
mst config get ui.pathDisplay # パス表示設定を取得
mst config get development.autoSetup # 自動セットアップ設定を取得
# 設定値を設定
mst config set ui.pathDisplay relative # 自動的にユーザー設定として保存
mst config set --user ui.pathDisplay relative # 明示的にユーザー設定に保存
mst config set --project worktrees.path "../" # 明示的にプロジェクト設定に保存
mst config set development.defaultEditor cursor # デフォルトエディタを設定(ユーザー設定)
# デフォルト値にリセット
mst config reset ui.pathDisplay # パス表示をデフォルトにリセット
mst config reset development.autoSetup # 自動セットアップをデフォルトにリセット
# 設定ファイルの表示と管理
mst config show # 現在の有効な設定を表示
mst config path # 設定ファイルの場所を表示
mst config init # プロジェクト設定を作成
```
**パス表示設定:**
`ui.pathDisplay` 設定は、すべてのコマンドでファイルパスがどのように表示されるかを制御します。`"relative"` に設定すると、現在の作業ディレクトリからの相対パスで表示されます。`"absolute"`(デフォルト)に設定すると、フル絶対パスで表示されます。この設定は `github`、`review`、`shell`、`exec`、`health` などのコマンドに影響します。
**Claude設定:**
- `markdownMode: "shared"` - メインリポジトリのCLAUDE.mdへのシンボリックリンクを作成(デフォルト)
- `markdownMode: "split"` - 各worktreeに独立したCLAUDE.mdファイルを作成
| カテゴリ | 主なキー | 役割 | 例 / デフォルト |
| ----------- | -------------- | --------------------------------------- | ----------------------------------- |
| worktrees | `path` | worktree(演奏者)の格納先 | `../maestro-{branch}` |
| | `directoryPrefix` | worktreeディレクトリのプレフィックス | `""` (空文字列) |
| | `branchPrefix` | 作成時のブランチ接頭辞 | `feature/` |
| development | `autoSetup` | 作成直後に `npm install` などを自動実行 | `true` |
| | `syncFiles` | 共有したいファイルの配列 | `[".env", ".env.local"]` |
| | `defaultEditor`| デフォルトのエディタ | `cursor` |
| tmux | `enabled` | tmux統合を有効化 | `false` |
| | `openIn` | ウィンドウかペインで開く | `window` (`window` または `pane`) |
| | `sessionNaming`| セッション名のパターン | `{branch}` |
| claude | `markdownMode` | CLAUDE.md ファイル管理モード | `shared` (`shared` または `split`) |
| github | `autoFetch` | 操作前に自動でfetch | `true` |
| | `branchNaming.prTemplate` | PRブランチ名テンプレート | `pr-{number}` |
| | `branchNaming.issueTemplate` | Issueブランチ名テンプレート | `issue-{number}` |
| ui | `pathDisplay` | パスを表示するすべてのコマンドでの表示形式 | `absolute` (`absolute` または `relative`) |
| hooks | `afterCreate` | 作成後に実行する任意コマンド | `npm install` |
| | `beforeDelete` | 退場前フック | `echo "Exiting $ORCHESTRA_MEMBER"` |
#### デフォルト値付き完全なサンプル
```json
{
"worktrees": {
"path": "../maestro-{branch}",
"directoryPrefix": "",
"branchPrefix": "feature/"
},
"development": {
"autoSetup": true,
"syncFiles": [".env", ".env.local"],
"defaultEditor": "cursor"
},
"tmux": {
"enabled": false,
"openIn": "window",
"sessionNaming": "{branch}"
},
"claude": {
"markdownMode": "shared"
},
"github": {
"autoFetch": true,
"branchNaming": {
"prTemplate": "pr-{number}",
"issueTemplate": "issue-{number}"
}
},
"ui": {
"pathDisplay": "absolute"
},
"hooks": {
"afterCreate": "npm install",
"beforeDelete": "echo \\\"演奏者が退場します: $ORCHESTRA_MEMBER\\\""
}
}
```
### 📋 完全な設定リファレンス
`.maestro.json`で利用可能なすべての設定オプション:
| カテゴリ | キー | 型 | デフォルト | 説明 |
|----------|-----|------|---------|-------------|
| **worktrees** | | | | worktreeの場所と命名 |
| | `path` | string | `"../maestro-{branch}"` | worktreeのディレクトリパターン(`{branch}`はブランチ名に置換) |
| | `directoryPrefix` | string | `""` | すべてのworktreeディレクトリ名に付加される接頭辞 |
| | `branchPrefix` | string | `""` | 新規ブランチ名のデフォルト接頭辞 |
| **development** | | | | 開発環境設定 |
| | `autoSetup` | boolean | `true` | worktree作成後にセットアップコマンドを自動実行 |
| | `syncFiles` | string[] | `[".env", ".env.local"]` | worktree間で同期するファイル |
| | `defaultEditor` | string | `"cursor"` | デフォルトエディタ(`vscode`、`cursor`、`none`) |
| **postCreate** | | | *(デフォルトなし)* | 作成後の自動化 |
| | `copyFiles` | string[] | - | 作成後にメインworktreeからコピーするファイル |
| | `commands` | string[] | - | worktree作成後に実行するコマンド |
| **tmux** | | | | tmux統合設定 |
| | `enabled` | boolean | `false` | tmux統合を有効化 |
| | `openIn` | string | `"window"` | `window`または`pane`で開く |
| | `sessionNaming` | string | `"{branch}"` | セッション名のパターン |
| **claude** | | | | Claude Code統合 |
| | `markdownMode` | string | `"shared"` | CLAUDE.mdモード:`shared`(シンボリックリンク)または`split`(独立) |
| **github** | | | | GitHub統合設定 |
| | `autoFetch` | boolean | `true` | 操作前の自動フェッチ |
| | `branchNaming.prTemplate` | string | `"pr-{number}"` | PRブランチ名テンプレート |
| | `branchNaming.issueTemplate` | string | `"issue-{number}"` | Issueブランチ名テンプレート |
| **ui** | | | | ユーザーインターフェース設定 |
| | `pathDisplay` | string | `"absolute"` | パス表示形式:`absolute`または`relative` |
| **hooks** | | | | ライフサイクルフック |
| | `afterCreate` | string \| string[] | - | worktree作成後に実行するコマンド |
| | `beforeDelete` | string | - | worktree削除前に実行するコマンド |
> **注**: 詳細な設定例と高度な使用方法については、[設定ガイド](./docs/CONFIGURATION.md)を参照してください。
### 🤖 MCP統合設定
最新のコマンドを使用してClaude CodeにMaestroをMCPサーバーとして追加:
#### ローカルスコープ(デフォルト - 現在のプロジェクトでのみ、個人専用)
```bash
claude mcp add maestro -s local -- npx -y @camoneart/maestro maestro-mcp-server
# または -s フラグなし(localがデフォルト)
claude mcp add maestro -- npx -y @camoneart/maestro maestro-mcp-server
```
#### プロジェクトスコープ(.mcp.jsonに保存、バージョン管理でチーム共有)
```bash
claude mcp add maestro -s project -- npx -y @camoneart/maestro maestro-mcp-server
```
#### ユーザースコープ(マシン上の全プロジェクトで利用可能)
```bash
claude mcp add maestro -s user -- npx -y @camoneart/maestro maestro-mcp-server
```
#### グローバルインストールの場合
Maestroをグローバルインストールしている場合は以下を使用:
```bash
claude mcp add maestro -s user -- maestro-mcp-server
```
これによりClaude CodeがMaestroのMCPサーバーを選択したスコープレベルで使用できるよう自動設定されます。
**注意**: 従来の`.claude/mcp_settings.json`への手動設定はサポートされなくなりました。`claude mcp add`コマンドを使用してください。
### シェル補完
Maestro は **Bash / zsh / fish** の補完スクリプトを提供します。
| インストール方法 | Bash | Zsh / Fish |
| ---------------- | --------------------------------------- | ----------- |
| Homebrew | 自動 (※ bash は bash-completion@2 必須) | 自動 |
| npm / pnpm | 手動 (下記) | 手動 (下記) |
#### Bash で手動設定 (npm 版など)
```bash
# 前提: bash-completion v2 をインストール済み
brew install bash-completion@2 # macOS の例
# .bashrc または .bash_profile に追記
eval "$(mst completion bash)"
```
#### zsh で手動設定
```bash
mkdir -p ~/.zsh/completions
mst completion zsh > ~/.zsh/completions/_mst
autoload -U compinit && compinit # 設定済みであれば不要
```
#### fish で手動設定
```bash
mst completion fish > ~/.config/fish/completions/mst.fish
```
## トラブルシューティング
### ❓ よくあるエラーと対処法
| エラー内容 | 主な原因 | ワンライン解決策 |
| ----------------------------------------- | -------------------------------- | --------------------------------- |
| **Git が古い**<br>`fatal: unknown option` | Git バージョン < 2.22 | `brew install git` |
| **fzf が見つからない** | fzf 未インストール | `brew install fzf` |
| **tmux が見つからない** | tmux 未インストール | `brew install tmux` |
| **tmux ペインが多すぎる**<br>`画面サイズに対してペイン数(N個)が多すぎるため、セッションが作成できませんでした` | ターミナルウィンドウに対してペイン数が過多 | ウィンドウのリサイズまたはペイン数を削減(最大:水平10個、垂直15個) |
| **GitHub PR/Issue が見つからない**<br>`Error: PR/Issue #999 が見つかりません` | 存在しないIssue/PR番号を指定 | 正しい番号を確認するか、リポジトリを確認 |
### その他のエラーコード例
| エラーコード | 原因 | 解決策 |
| ------------ | ------------------------------ | ----------------------------------- |
| `ENOENT` | Git 実行ファイルが見つからない | Git の PATH を確認、再インストール |
### ⚠️ CLIオプション検証とエラーハンドリング
Maestroは**厳密なCLIオプション検証機能**を搭載し、無効なオプションでの実行を防ぎます:
**無効なオプションでの即座終了**:
- **早期検出**: 未知の無効なオプションが提供された際、コマンドが即座に終了
- **実行を阻止**: 無効なオプションが検出された場合、いかなる操作も実行されない
- **明確なエラーメッセージ**: どのオプションが無効かについて具体的なフィードバック
**例**:
```bash
# 無効なオプションが提供された場合:
mst create feature/test --invalid-option value
# 出力:
error: unknown option '--invalid-option'
# エラーコード1でコマンド終了 - リソースは作成されない
```
**メリット**:
- **意図しない操作を防止**: オプション名のタイプミスでコマンドが実行されない
- **クリーンな終了**: エラーコード1での即座フィードバック
- **より良い開発者体験**: コマンド使用エラーについて即座フィードバック
### ⚠️ 既存ディレクトリチェックとインタラクティブ処理
Maestroには、worktree作成時に**既存ディレクトリの検出と対話的な解決オプション**を提供する機能が搭載されています:
**スマートなディレクトリ管理**:
- **早期検出**: worktree作成前にターゲットディレクトリの存在をチェック
- **対話的な解決**: 競合発生時に複数の解決オプションをユーザーに提示
- **一貫した処理**: create、github、reviewコマンド全体で統一された動作
- **安全な操作**: すべての操作に確認プロンプトと明確なフィードバックを含む
**利用可能な解決オプション**:
既存のディレクトリが検出された場合、Maestroは以下の選択肢を提供します:
- **削除して再作成**: 既存ディレクトリを削除し、新しいworktreeを作成
- **別名を使用**: 自動的にユニークなディレクトリ名を生成(例:`branch-name-2`)
- **操作をキャンセル**: 変更を加えずに安全に終了
**改善されたユーザー体験**:
```bash
# ディレクトリが存在する場合の対話例:
mst create feature/new-feature
⚠️ ディレクトリ '../feature/new-feature' は既に存在します
? どのように処理しますか?
❯ 既存ディレクトリを削除して新規作成
別の名前を使用(feature/new-feature-2など)
キャンセル
```
**メリット**:
- **競合を防止**: 既存ディレクトリによるworktree作成失敗をなくす
- **ユーザー制御**: 既存ディレクトリの処理方法を明確に選択可能
- **自動代替案**: 必要に応じてスマートに代替名を生成
- **安全なキャンセル**: 競合を解決できない場合の簡単な終了オプション
### ⚠️ tmux マルチペイン検証とエラーハンドリング
Maestroは**tmuxペイン作成の事前検証機能**も搭載し、リソースの無駄遣いを防ぎ、より良いユーザー体験を提供します:
**スマート事前検証機能**:
- **早期検出**: リソース(worktree、ブランチ、tmuxセッション)を作成する前にペイン数制限を検証
- **リソース作成を阻止**: 検証に失敗した場合、即座にエラーコード1で終了
- **クリーンアップ不要**: リソースが作成されないため、ロールバックの必要がない
- **最大制限**: 水平分割は最大10ペイン、垂直分割は最大15ペイン
**改善されたエラーメッセージ**:
```bash
# 事前検証エラーメッセージ:
Error: 画面サイズに対してペイン数(20個)が多すぎるため、セッションが作成できませんでした。ターミナルウィンドウを大きくするか、ペイン数を減らしてください。(水平分割)
# コマンドは即座に終了 - リソースは作成されない
```
**クイック解決法**:
```bash
# ペイン制限が原因で失敗する場合:
mst create feature/api --tmux-h-panes 20
# 許可制限内に削減:
mst create feature/api --tmux-h-panes 8
# より高い制限の垂直分割に変更:
mst create feature/api --tmux-v-panes 12 --tmux-layout main-vertical
# 効率的なレイアウトを使用:
mst create feature/api --tmux-h-panes 6 --tmux-layout tiled
```
**検証機能のメリット**:
- **クリーンな終了**: 検証失敗時にエラーコード1で終了
- **リソース無駄を防止**: クリーンアップが必要なworktreeの作成を防ぐ
- **パフォーマンス向上**: tmux操作を待たずに即座にフィードバック
- **明確なガイダンス**: 実行可能な解決策を含む具体的なエラーメッセージ
**ペイン制限**:
- **水平分割**: 最大10ペイン(ペインあたりの画面領域が小さい)
- **垂直分割**: 最大15ペイン(垂直方向により多くの領域が利用可能)
- **検証トリガー**: マルチペインオプション(`--tmux-h-panes` > 2、`--tmux-v-panes` > 2)使用時のみ
上記で解決しない場合は [Issues](https://github.com/camoneart/maestro/issues) で検索または新規 Issue を作成してください。
### 🔍 デバッグモード
```bash
# すべての内部ログを表示
DEBUG=mst:* mst create feature/debug
# 詳細なログをファイルに保存
DEBUG=mst:* mst review --auto-flow &> maestro-debug.log
```
## 貢献
### 🤝 コントリビューションの流れ
1. [**Issue**](https://github.com/camoneart/maestro/issues) でバグ報告・機能提案を送る
2. このリポジトリを **Fork** し、`feat/your-topic` などのブランチを作成
3. 開発後 `pnpm lint && pnpm test` でスタイルとテストを通過させる
4. **Conventional Commits** 形式でコミット
5. Pull Request を作成し、レビューテンプレに沿って概要を記入
詳細は [Contributing Guide](/CONTRIBUTING.md) と [Code of Conduct](/CODE_OF_CONDUCT.md) を参照してください。
## ライセンス
Licensed under the [MIT License](./LICENSE).