日々の開発ループ
contributor の inner loop は /wt + dev-lifecycle skill です。docker compose ではありません。 docker-compose.selfhost.yml は顧客向けセルフホストデプロイ用のバンドルで、日々の開発では登場しません(リポジトリ取得と環境構築 参照)。backend/frontend はホスト側で直接プロセスとして動きます。
/wt — worktree オーケストレーター
複数の変更を並行で進めるとき、1 つの checkout を使い回すとブランチの切り替えのたびに DB・ポート・node_modules が衝突します。/wt はこれを解決する仕組みで、変更ごとに独立した git worktree(.claude/worktrees/<name>)を作り、DB・ポート・MinIO の key-prefix をすべて自動で分離します。
コマンド
| コマンド | やること |
|---|---|
/wt start <name> | worktree を作成(.claude/worktrees/<name>、ブランチ feat/<name>)。frontend の node_modules を main からシンボリックリンク。スロット (1-9) を割り当て、DB (astarmanagement_dev_wt<N>) を作成し、Caddy proxy に反映。既定では backend/frontend を起動しません(provision のみ) |
/wt start <name> --with-server | 上記に加えて backend/frontend も起動(start + serve を一度に) |
/wt serve <name> | start 済みの worktree に対して backend/frontend を起動。すでに動いていれば何もしない(冪等) |
/wt sync <name> | その worktree 自身の backend に対して openapi:all を実行し、frontend の型 (api.d.ts / zod-client.ts) を再生成 |
/wt verify <name> | 変更ファイルと必要な検証レイヤー (L1〜L4) を表示 |
/wt ship <name> | 検証 → main が clean なことを確認 → --no-ff で merge → worktree を片付け |
/wt cleanup <name> | サービス停止・DB 削除・スロット解放・git worktree 削除・ブランチ削除 |
/wt status | 稼働中の worktree 一覧 |
start が provision-only(起動しない) なのが重要な設計判断です。worktree を作るだけならメモリを消費しないので、並行で何個でも作って構いません。実際にサーバーが必要になったときだけ serve します。
スロットによるポート・DB 分離
各 worktree にはスロット番号(0-9、main は常に 0)が割り当てられ、全サービスのポートと DB 名がそこから決定論的に導出されます。
| サービス | slot 0 (main) | slot N |
|---|---|---|
| Backend | 8080 | 8080 + N |
| Frontend | 3000 | 3000 + N |
| Storybook | 6006 | 6006 + N |
| DB | astarmanagement_dev | astarmanagement_dev_wt<N> |
| MinIO key prefix | tenant/local | tenant/local-wt<N> |
PostgreSQL・MinIO のコンテナ自体は全 worktree で共有(astarmanagement-postgres-dev など)。DB 名とポート番号だけで分離しているので、コンテナを worktree ごとに何個も立てる必要がありません。
dev-lifecycle skill — プロセスの起動・停止
/wt serve の内部、あるいは main checkout(slot 0)で直接作業するときは、dev-lifecycle skill (lifecycle.sh) が backend(Spring Boot)・frontend(Nuxt dev server)・Storybook の起動・停止・再起動・状態確認を担当します。
.claude/skills/dev-lifecycle/lifecycle.sh status
.claude/skills/dev-lifecycle/lifecycle.sh start backend
.claude/skills/dev-lifecycle/lifecycle.sh restart backend --profile dev
.claude/skills/dev-lifecycle/lifecycle.sh stop all
lsof + PID ファイルで既存プロセスを検出し、グレースフルシャットダウン(SIGTERM → 5 秒後 SIGKILL)とヘルスチェック(/actuator/health など)でポーリングします。
./gradlew bootRun や bun run dev を直接実行することは settings.json の deny 設定で禁止されています。dev-lifecycle skill 経由でのみ起動できます。理由は、直接起動だと孤立プロセス(PID ファイルなしで動き続けるプロセス)が発生しやすく、複数セッションが並行するとポート競合や「誰が何を動かしているか分からない」状態になりやすいためです。
実装はコードを書く前に worktree に入る
コード変更は必ず worktree の中で行います。main の checkout を直接編集することはありません(hook で強制されています)。設計・スペック作成・レビューは main(read-only)で行い、/wt start で worktree ができたところから実装に入ります。
Astar Works の開発では、実装そのものは専用の実装エージェント(Sonnet ベースの worker)に委譲するのが規約です。メインの調査・設計セッションは実装コードを直接書かず、確定した設計とファイル一覧を worker に渡し、実装後に diff レベルでレビュー・検証してから /wt ship します。人間のエンジニアがこのリポジトリで作業する場合も、この「worktree を作ってから着手する」「変更後は検証してから ship する」というループ自体は同じです。
まとめ — 1 周の流れ
/wt start <name>— worktree を作る(provision のみ)/wt serve <name>— backend/frontend を起動- 変更を加える(worktree の中で)
- API を変更したら
/wt sync <name>で frontend の型を再生成 - 検証の 4 層 に沿って検証
/wt ship <name>— 検証 → merge → 片付け
次は 検証の 4 層 で、上記 5 の中身を詳しく見ます。