roblox-toolchain について
roblox-toolchainは、ファイルを中心にRobloxゲームを開発するためのエージェントスキルです。Rojo、Rokit、WallyまたはPesdeによるプロジェクト設定、ファイルとDataModelの対応、ツールのバージョン固定、Luau LSPの設定を解説します。
主な機能
- 01Rojoによるファイルベース開発ガイド
- 02Rokitでツールのバージョン固定
- 03WallyまたはPesdeで依存関係を管理
- 04プロジェクトファイルとDataModelの対応付け
- 05Luau LSPのsourcemap設定
- 06既存コードベースに合わせた統合ルール
活用シーン
- 01ファイルからRobloxゲームを開発
- 02チームでRojoなどのツール版を固定
- 03WallyまたはPesdeの依存関係を設定
- 04Luau LSPの補完を設定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ afrxo/ roblox-agent-skills --skill roblox-toolchainインストール後、Claude Code で/roblox-toolchainを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
examples/.gitkeepci.ymldefault.project.jsonfile-tree.mdpesde.tomlrokit.tomlwally.tomlreferences/luau-lsp-setup.mdpesde-manifest.mdproject-format.mdsync-mapping.mdwally-manifest.md詳細
Roblox Rojo(ファイルシステムを使ったワークフロー)
Studio 内ではなくディスク上のファイルを使って Roblox ゲームを開発する方法です。情報源:rojo.space(Rojo 公式ドキュメント)、github.com/rojo-rbx/rojo(Rojo のソース)、github.com/rojo-rbx/rokit(Rokit ツールチェーンマネージャー。Aftman/Foreman ではなくこちらを使用)、github.com/UpliftGames/wally(Wally パッケージマネージャー)、github.com/pesde-pkg/pesde(Pesde。新しい代替パッケージマネージャー)。ツール:stylua、selene、luau-lsp。
詳しくは、以下を参照してください。
references/project-format.md—.project.jsonの完全なスキーマreferences/sync-mapping.md— Rojo が認識するすべてのファイル拡張子と、それぞれの変換先references/wally-manifest.md—wally.toml、ロックファイル、コマンドの完全なリファレンスreferences/pesde-manifest.md—pesde.tomlの完全なスキーマ、環境、Wally ブリッジreferences/luau-lsp-setup.md— sourcemap の再生成、LSP の設定
統合ポリシー
このスキルでは推奨パターンを説明していますが、既存のコードを書き換えることを許可するものではありません。ルールは新しいコードと、ユーザーが明示的に依頼した変更に適用してください。**コードベースで既に使われているツールチェーンに合わせてください。**プロジェクトで Aftman が使われている場合は、求められていない限り Rokit への移行を行わないでください。Wally が使われている場合は、Pesde を提案しないでください。default.project.json が特定の構造に従っている場合は、書き換えずに拡張してください。競合があれば一度だけ指摘し、既存の設定を優先してください。
ルールの全文:../../shared/integration-policy.md。
原則
- **唯一の信頼できる情報源はファイルシステムです。**リポジトリが正本で、Studio はビルド対象です。
- ツールチェーンのバージョンはプロジェクトごとに固定します。
rokit.tomlにはrojo、wally(またはpesde)、stylua、selene、luau-lspの正確なバージョンを記載します。「自分の環境では動く」より、再現可能なビルドを優先してください。 - **sourcemap はコミットせず、再生成します。**生成される出力です。依存関係が変更されたら再生成してください。
- CI でビルドと lint を実行します。
mainがグリーンなら、rojo buildが有効な.rbxlを生成し、lint も合格していることを意味します。 - **
Packages/は生成物です。**Wally が生成するもので、手動編集はしません。また、.gitignoreに含めます。
Rojo の基本
インストール
Rokit(Foreman/Aftman の後継となるツールチェーンマネージャー)を使い、プロジェクトごとにバージョンを固定します。
# rokit.toml — drop-in compatible with foreman.toml / aftman.toml format
[tools]
rojo = "rojo-rbx/[email protected]"
wally = "UpliftGames/[email protected]"
stylua = "JohnnyMorganz/[email protected]"
selene = "Kampfkarren/[email protected]"
その後、プロジェクトのルートで rokit install を実行すると、指定した正確なバージョンが取得されます。グローバルにインストールされたツールに頼らないでください。マシンごとにバージョンがずれていきます。
**Aftman ではなく Rokit を使う理由:**Aftman はメンテナンスされていません(サードパーティの作者は Roblox での業務を終了しています)。Foreman は Roblox によってメンテナンスされていますが、内部利用向けです。Rokit はコミュニティによってメンテナンスされており、どちらのマニフェスト形式ともそのまま互換性があり、インストールも大幅に高速です。移行するには、aftman.toml を rokit.toml に名前変更します。
Rokit の一般的なコマンド:rokit init、rokit add OWNER/REPO、rokit install、rokit update、rokit list、rokit self-update。
2 つのモード
# Live sync — Studio plugin connects to this server, applies changes as you save.
rojo serve [path/to/project.json]
# One-shot build — produces a .rbxl (place) or .rbxm (model).
rojo build [path/to/project.json] --output build/place.rbxl
rojo serve は開発用です。rojo build は CI と最終的な公開用です。ライブ変更を実際に適用するのは、Studio のプラグインタブからインストールする、CLI とバージョンを合わせた Studio プラグインです。
プロジェクトファイルの場所
Rojo は現在のディレクトリにある default.project.json を探します。別の .project.json ファイルを使うには、明示的にパスを指定してください。複数のビルド対象(ゲーム、プラグイン、ライブラリ)があるリポジトリでは、通常、対象ごとにプロジェクトを 1 つ用意します。
default.project.json の構造
{
"name": "MyGame",
"tree": {
"$className": "DataModel",
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"$path": "src/ReplicatedStorage"
},
"ServerScriptService": {
"$className": "ServerScriptService",
"$path": "src/ServerScriptService"
},
"StarterPlayer": {
"$className": "StarterPlayer",
"StarterPlayerScripts": {
"$className": "StarterPlayerScripts",
"$path": "src/StarterPlayerScripts"
}
},
"Workspace": {
"$className": "Workspace",
"$properties": {
"Gravity": 196.2
}
}
}
}
name(必須)— ビルド成果物の名前として使用されます。tree(必須)— ルート Instance の記述です。tree内:$className— Instance のクラスです。$pathで解決される場合、またはキーがサービス名の場合は省略可能です。$path— この Instance の下にマウントするディスク上のフォルダー/ファイルです。$properties— 設定するプロパティです(例:Gravity、HttpEnabled)。$ignoreUnknownInstances—trueの場合、Rojo は同期しなかった Instance を削除せず、そのまま残します。- その他のキー — 子 Instance の記述です。
その他のトップレベルフィールド:servePort(デフォルトは 34872)、servePlaceIds(誤って別のゲームに同期しないようにするための place ID の許可リスト)、placeId、gameId、serveAddress、globIgnorePaths、emitLegacyScripts。
emitLegacyScripts は、*.server.luau/*.client.luau が、レガシーな Script/LocalScript Instance を生成するか、RunContext が設定された Script Instance を生成するかを制御します。ドキュメントに記載されているデフォルトは true です。決めつける前に、インストール済みの Rojo のバージョン(rojo --version とリリースノート)を確認してください。新しいプロジェクトでは、最新の RunContext を使用するために false を設定してください。roblox-dev の script-types セクションを参照してください。
スキーマの全容:references/project-format.md。
ファイルシステムから DataModel へのマッピング
これは頻繁に参照するルールです。よく使うものを覚えておきましょう。
| ディスク上のパス | 変換後 |
|---|---|
dir/(任意のディレクトリ) | Folder |
foo.luau | foo という名前の ModuleScript(Rojo はレガシーな .lua も受け付けます) |
foo.server.luau | foo という名前の Script(サーバー) |
foo.client.luau | foo という名前の LocalScript(クライアント) |
dir/init.luau | dir という名前の ModuleScript(ディレクトリがスクリプトになります) |
dir/init.server.luau | dir という名前の Script(ディレクトリがサーバースクリプトになります) |
dir/init.client.luau | dir という名前の LocalScript(ディレクトリがローカルスクリプトになります) |
foo.rbxm/foo.rbxmx | バイナリ/XML 形式のモデル |
foo.csv | LocalizationTable |
foo.txt | StringValue |
foo.json(.model.json/.project.json 以外) | テーブルを返す ModuleScript |
foo.toml | テーブルを返す ModuleScript |
foo.model.json | JSON で記述されたモデル(手書き用。RemoteEvent などに便利) |
foo.project.json | ネストされたプロジェクト(親に合成されます) |
foo.meta.json | 対応するファイル/ディレクトリに付加されるメタデータのサイドカーファイル |
init.luau のセマンティクス
ディレクトリと init.luau は 1 つの ModuleScript になり、そのディレクトリ内のほかの子要素は、そのスクリプトの子要素になります。別のフォルダーを作らずに、スクリプトにサブモジュールを持たせることができます。
src/Inventory/
├── init.luau # ModuleScript "Inventory"
├── add.luau # ModuleScript "add" (child of Inventory)
├── remove.luau # ModuleScript "remove"
└── types.luau # ModuleScript "types"
各ディレクトリに置ける init.* ファイルは 1 つだけです(init.luau、init.server.luau、init.client.luau のいずれか 1 つ)。
Meta ファイル
foo.meta.json は、Rojo 固有のメタデータを foo.* に付加します。一般的な用途:
// init.meta.json — turn the parent folder into a Tool with a Grip
{
"className": "Tool",
"properties": {
"Grip": [0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1]
}
}
// foo.meta.json — disable a script
{
"properties": { "Disabled": true }
}
// hello.meta.json — let Rojo leave Instances under hello.txt alone
{
"ignoreUnknownInstances": true
}
className が機能するのは init.meta.json のみです。properties はモデル以外の任意のファイルで機能します。
マッピング表の全容:references/sync-mapping.md。
推奨されるプロジェクト構成
my-game/
├── rokit.toml # toolchain pinning
├── default.project.json # Rojo project file
├── wally.toml # package manifest
├── wally.lock # lockfile (committed)
├── stylua.toml # formatter config
├── selene.toml # linter config
├── sourcemap.json # generated; .gitignore'd
├── Packages/ # wally output; .gitignore'd
├── ServerPackages/ # wally output; .gitignore'd
├── DevPackages/ # wally output; .gitignore'd
├── .github/workflows/ci.yml # CI
├── (editor config) # .vscode/settings.json, .nvim, etc. — editor-specific
├── .gitignore
├── README.md
└── src/
├── ReplicatedStorage/
│ ├── Shared/
│ │ ├── init.luau
│ │ └── ...
│ └── Client/ # (optional) client-only scripts via RunContext
├── ServerScriptService/
│ ├── init.server.luau
│ └── Systems/
└── StarterPlayer/
└── StarterPlayerScripts/
└── init.client.luau
src/ のディレクトリ名を DataModel のマウント先に合わせてください。パスを見れば、コードがどこで実行されるか正確に分かります。
Wally(パッケージ)
Rokit 経由でインストールしてください(グローバルから取得しないでください)。rokit.toml に追加します。
[tools]
wally = "UpliftGames/[email protected]"
次に rokit install を実行します。コマンド:
wally init # scaffold wally.toml
wally install # download deps into Packages/
wally install --locked # CI; fail if lockfile is stale
wally update [name...] # bump deps
wally publish # push your package to the registry
wally search <query> # find packages
wally.toml
[package]
name = "yourname/coolpkg" # SCOPE/NAME, lowercase, dashes ok
version = "1.0.0" # SemVer
license = "MIT" # SPDX
authors = ["Your Name <[email protected]>"]
realm = "shared" # "shared" or "server"
registry = "https://github.com/UpliftGames/wally-index"
[dependencies]
React = "jsdotlua/[email protected]"
Promise = "evaera/[email protected]"
[server-dependencies]
ProfileService = "loleris/[email protected]"
[dev-dependencies]
Jest = "jsdotlua/[email protected]"
Realm
shared— クライアントに複製されます。ReplicatedStorageの下にマウントします。server— サーバー専用です。ServerStorageまたはServerScriptServiceの下にマウントします。clientrealm はありません。クライアント専用の依存関係はsharedに配置し、インポートによってクライアント上で実行します。
Rojo での Wally 出力のマウント
"ReplicatedStorage": {
"$className": "ReplicatedStorage",
"Packages": {
"$path": "Packages"
}
},
"ServerScriptService": {
"$className": "ServerScriptService",
"Packages": {
"$path": "ServerPackages"
}
}
パッケージは realm ごとに別のフォルダーにインストールされます。Shared は Packages/、server は ServerPackages/、dev は DevPackages/ に配置されます。
Lockfile
wally.lock には、すべての依存関係(推移的依存関係を含む)の正確なバージョンが固定されます。コミットしてください。 CI で wally install --locked を実行すると、全員が同じものをビルドできます。
マニフェストの全フィールド、ロックファイルの形式、コマンド一覧については、references/wally-manifest.md を参照してください。
Pesde(代替パッケージマネージャー)
Pesde は、新しい Luau ファーストのパッケージマネージャーです。ランタイムのロックインを防ぐよう設計されています。1 つのツールで複数の Luau ランタイム(luau、lune、roblox、roblox_server)を対象にでき、ブリッジ経由で既存の Wally レジストリからパッケージを取得できます。次のような場合におすすめです。
- 純粋な Luau、Lune、Roblox のプロジェクト全体で、パッケージマネージャーを統一したい場合。
- 同じプロジェクトで Wally パッケージとネイティブの pesde パッケージの両方が必要な場合。
- Wally の Cargo 風の操作性よりも、npm/pnpm 風の操作性を好む場合。
pesde.toml
name = "yourname/coolpkg"
version = "1.0.0"
license = "MIT"
[target]
environment = "roblox" # luau | lune | roblox | roblox_server
lib = "src/init.luau"
[indices]
default = "https://github.com/pesde-pkg/index"
[wally_indices]
default = "https://github.com/UpliftGames/wally-index"
[dependencies]
# Native pesde dep
hello = { name = "pesde/hello", version = "^1.0.0" }
# Wally dep via the bridge
React = { wally = "jsdotlua/react", version = "^17.1.0" }
[dev_dependencies]
Jest = { wally = "jsdotlua/jest", version = "^3.10.0" }
コマンド
pesde init # scaffold pesde.toml
pesde add SCOPE/NAME # add + install a dep
pesde install # install all deps; writes pesde.lock
pesde run # run [scripts] entries (uses Lune)
pesde publish
ディレクトリ構成
- ネイティブの pesde 依存関係は、ターゲット名のフォルダー(
roblox_packages/、luau_packages/など)にインストールされます。 - Wally ブリッジの依存関係は、引き続き wally-index リポジトリ経由で解決されます。
pesde.lockがロックファイルです。コミットしてください。- Roblox プロジェクトでは、pesde はスクリプトパッケージ経由で Rojo 互換のソースマップを生成します。
rojo sourcemapと組み合わせてください。
どちらを選ぶか
| 必要なもの | 選択肢 |
|---|---|
| 成熟していて、Roblox 専用で、大規模な既存エコシステム | Wally |
| 複数のランタイム(Lune CLI ツール、Roblox、プレーンな Luau) | Pesde |
| Cargo 風の操作性 | Wally |
| npm/pnpm 風の操作性と Wally ブリッジ | Pesde |
| Wally を使っている既存のプロジェクトで、特に問題がない | そのまま使う |
Wally と Pesde は、そのまま置き換えられるものではありません。マニフェスト形式と依存関係の解決方法が異なります。理由もなく、プロジェクトの途中で切り替えないでください。
ソースマップ(Luau LSP)
Luau LSP が適切な自動補完と require() の解決を行うには、ファイルが DataModel 内のどこに対応するかを把握する必要があります。Rojo がマップを生成します。
# Watch mode — regenerates on filesystem change
rojo sourcemap --watch --output sourcemap.json default.project.json
# One-shot
rojo sourcemap --output sourcemap.json default.project.json
次に、luau-lsp にマップを指定します。エディターごとの設定は次のとおりです。
- VS Code(
luau-lsp拡張機能):.vscode/settings.json(またはワークスペースレベルの設定)に"luau-lsp.sourcemap.sourcemapFile": "sourcemap.json"を記述します。 - Neovim / Helix / Sublime: LSP の起動引数(
--definitions=.../--sourcemap=...)または LSP クライアントの設定から、ソースマップのパスを渡します。luau-lspバイナリのドキュメントにフラグが記載されています。 - CLI モード:
luau-lsp analyze --sourcemap sourcemap.json ...を実行します。正確なフラグは、インストール済みのluau-lsp --helpで確認してください。
次の後に再生成してください。
- プロジェクト内のファイルを追加または削除したとき。
wally installを実行したとき(新しいパッケージパスが追加されます)。default.project.jsonのマウントを変更したとき。
一般的なワークフローでは、ターミナルで rojo sourcemap --watch を実行しながら、rojo serve も実行します。どちらもセッション中は実行し続けます。
sourcemap.json は生成物なので、.gitignore に追加してください。
LSP の設定の詳細については、references/luau-lsp-setup.md を参照してください。
リントとフォーマット
StyLua(フォーマッター)
# stylua.toml
column_width = 100
line_endings = "Unix"
indent_type = "Tabs" # or "Spaces" with indent_width = 4
quote_style = "AutoPreferDouble"
call_parentheses = "Always"
[sort_requires]
enabled = true # alphabetize the require block; pairs with luau-expert guidance
stylua src/ で実行します。StyLua 拡張機能をインストールすれば、ほとんどのエディターで保存時に自動フォーマットできます。
selene(リンター)
# selene.toml
std = "roblox" # roblox stdlib definitions
# Optional: per-rule tweaks
[config]
incorrect_standard_library_use = "warn"
重要なのは std = "roblox" の指定です。これがないと、selene はすべての Instance.new と task.wait に警告を出します。selene src/ で実行します。
Luau LSP(型チェッカー)
luau-lsp は、エディター内での型チェック、ホバー情報、自動補完を提供します。網羅性を最大限に高めるには、ファイルごとに --!strict と組み合わせてください(luau-expert スキルを参照)。
プロジェクトレベルの設定(.luaurc):
{
"languageMode": "strict",
"lint": {
"*": true
}
}
スキーマは luau.org/lint で確認してください。.luaurc のフィールドは変更される場合があります。
CI
最小限の CI 実行手順:
- Rokit をセットアップ(
rokit install)して、固定されたバージョンのツールをインストールします。 wally install --locked— ロックファイルに差異があれば失敗します。stylua --check src/— フォーマットに差異があれば失敗します。selene src/— lint を実行します。rojo sourcemap --output sourcemap.json default.project.json— マップを生成します。- ソースマップを使用して
luau-lsp analyze— 型チェックを行います。正確なフラグはインストールされているバージョンによって異なります(--sourcemapまたは--definitions)。luau-lsp --helpを確認してください。 rojo build default.project.json --output build/place.rbxl— ビルド成果物を生成します。- (任意)
place.rbxlを成果物としてアップロード/公開します。
各ステップで失敗すると、次のステップには進みません。CI が成功すれば、ツールのバージョンが固定され、依存関係がロックされ、フォーマットと lint、型チェックに問題がなく、ビルドも成功したことを意味します。
GitHub Actions の例は examples/ci.yml にあります。
検証ルール
.project.jsonのフィールド名は、name、tree、$className、$path、$properties以外を記憶に頼って記載しないでください。スキーマ全体は短いため、あまり一般的でないフィールドを使用する前にreferences/project-format.mdを確認してください。- Wally のバージョン指定の仕様を記憶に頼って説明しないでください。Wally はデフォルトで
^を使用し、Cargo 方式の SemVer に従います。~、=、*の詳細を確認し、デフォルト以外のバージョン指定子を推奨する前に Wally のドキュメント を参照してください。 emitLegacyScriptsのデフォルト値はリリースによって変わっています。ScriptとScript(RunContext=Server)の違いを前提とする前に、プロジェクトで使用している Rojo のバージョン(rojo --version)を確認してください。- エディターの設定は異なります。 このスキルが対象とするのは Luau LSP レイヤーです。参考資料にある
.vscode/settings.jsonの例は説明用です。Neovim/Helix/Sublime を使用する場合は、対応する設定項目を設定してください。 - Rojo とエンジンを混同しないでください。
RunContextの配置、レプリケーション、DataModel の仕様はroblox-devの対象です。このスキルの対象は「ファイルがこの DataModel パスに配置される」までです。
アンチパターン
| ❌ やってはいけないこと | ✅ こうしましょう |
|---|---|
グローバルにインストールした rojo/wally/stylua を使う | rokit.toml でプロジェクトごとにバージョンを固定する |
| 新しいプロジェクトで Aftman または Foreman を使う | Rokit を使う(ドロップインの後継で、コミュニティによって保守されており、より高速です) |
Packages/ を手動で編集する | 生成物として扱う。wally install で再生成されます |
Packages//ServerPackages//DevPackages/ をコミットする | .gitignore に追加する |
sourcemap.json をコミットする | .gitignore に追加し、必要に応じて再生成する |
wally.lock を Git に追加し忘れる | コミットする。CI では --locked を使用します |
1 つのフォルダーに複数の init.* を置く | ディレクトリごとに init スクリプトを 1 つだけ置き、代わりにサブモジュールを使う |
ServerScriptService のマウント先に init.client.luau を置く | スクリプトの種類をコンテナーに合わせる |
std = "roblox" を設定せずに selene を使う | 必ず設定する。設定しないと、Roblox API のすべてで lint エラーになります |
| Studio とファイルシステムを同時に編集する | ファイルシステムを正とする。rojo serve を実行していないときは Studio を閉じる |
rojo build で生成した place ファイルをチェックインする | CI の成果物のみとする。バイナリの place ファイルは差分を確認できません |
Packages を ReplicatedStorage のみにマウントし、サーバー用依存関係も使用する | ServerPackages をサーバーコンテナーに個別にマウントする |
クライアント動作を期待して、StarterPlayerScripts のマウント先に通常の *.luau を置く | *.client.luau(レガシー)または RunContext=Client の Script を使う |
保存のたびに rojo sourcemap を手動で再実行する | 長時間実行するターミナルで --watch を使う |
作業ツリーが汚れた状態で wally publish を実行する | クリーンなコミットにタグを付け、CI から公開する |
ソースマップなしで luau-lsp を使う | ソースマップを生成する。LSP は require() の解決にソースマップを必要とします |
例
examples/default.project.json— 標準的なマウントをすべて網羅した、一般的な配置のプロジェクトです。examples/wally.toml—[dependencies]、[server-dependencies]、[dev-dependencies]を含む、注釈付きの Wally マニフェストです。examples/pesde.toml—[target]、[indices]、[wally_indices]、[dependencies]を含む、注釈付きの Pesde マニフェストです。examples/rokit.toml— ツールチェーンのバージョン固定です。examples/file-tree.md— ファイルシステムと DataModel の対応を示す、リポジトリ全体のレイアウトです。examples/ci.yml— GitHub Actions ワークフローです。Rokit のインストール → wally install --locked → stylua check → selene → rojo build の順に実行します。