Claude Code と一緒に Rust 製の CLI を作るのが楽しくて、ここ最近で shun / rvpm / todoke / yui / renri といった CLI がどんどん増えていきました。これらにまったく同じボイラープレートを適用しつづけるためのメタテンプレート CLI、kata (型) を作りました。
型 — the woodblock pattern. 各プロジェクトに同じ型を押し当てる、版木のイメージです。
なぜ作ったのか
同じような CLI が増えてくると、共通ボイラープレートのメンテがどんどんしんどくなります。具体的にしんどかったのはこのあたりです。
Makefile.tomlのcheck/clippy/testタスクの並び.github/workflows/ci.ymlの OS マトリクスと action のバージョン pin.github/workflows/release.ymlの cross-compile + cargo publish のテンプレrustfmt.toml/clippy.toml/rust-toolchain.tomlの方針apm.ymlで APM 経由の AI エージェント用 skill (renriなど) を入れる定型renovate.jsonの auto-merge ルール- そして極めつけに
AGENTS.md/CLAUDE.md/GEMINI.md
最後の AGENTS.md がいちばんやっかいでした。Claude / Gemini / Codex に渡している「PR レビューはこう回す」「worktree workflow はこう」「Rust の lint/format ポリシーはこう」みたいな会話で蓄積されたノウハウを、新しいプロジェクトを生やすたびに、あるいは規約を 1 行直すたびに、N 個のリポジトリにぜんぶ手でコピペする必要があったのです。
「Gemini Code Assist と CodeRabbit 両方のレビュー待つようにしよう」と気付いたら 7 個のリポジトリの AGENTS.md を全部開いて編集する、というのを何度かやりました。1 回ならいいんですけど、規約は一度決めて終わりじゃなくて、運用しながら何度も微調整したくなる。
copier / cookiecutter / cruft といった既存ツールは「最初のプロジェクト生成」と「機械的な再適用」までは面倒を見てくれるんですが、AGENTS.md のように
- リポジトリ共通のセクション (PR レビュー規約、worktree workflow)
- プロジェクト固有のセクション (このプロジェクトのアーキ概要、特殊な事情)
が1 枚のファイルに同居しているようなものを update し続ける機能はありませんでした。AI に判定を委譲するモードもありません。
そこで作ったのが kata です。「型 (テンプレート) を版木のように押し当てて、押し当てきれないところだけ AI に判断させる」 という発想で設計しました。
kata の特徴
- layered template —
pj-base+pj-rust+pj-rust-cliを順に重ねて、後勝ち。言語非依存な部分をpj-baseに集約できる how×whenの二軸 —how(overwrite/merge-section/merge-toml/merge-yaml/ai/script) とwhen(once/always/manual) が独立。how="ai", when="once"とhow="script", when="always"がどちらも自然に書ける- marker-bracketed merge-section —
AGENTS.mdの<!-- kata:agents:base:begin -->~<!-- kata:agents:base:end -->の間だけを kata が管理。プロジェクト固有の節は外側にいくらでも書ける - path-based merge-toml —
Makefile.tomlのtasks.check/tasks.clippy/tasks.testだけを kata が所有して、tasks.install-localのような独自タスクは触らない - AI 委譲 —
how = "ai"なファイルは、インストール済みのclaude/gemini/codexCLI に template の diff と現在の中身を投げて、chezmoi 風の[a]ccept / [e]dit / [s]kip / [d]eferで確認 - truth は PJ 側 — どのテンプレートをどの rev で適用したかは各 PJ の
.kata/applied.tomlに記録される。グローバル設定は単なる PJ パスのレジストリ - 並列実行 — tokio で PJ をファンアウト、AI 呼び出しは semaphore で抑制してエージェント CLI の同時起動が爆発しないようにする
- CI 同期 —
kata-apply.ymlを pj-base が配布。daily でkata update + kata applyを回して、テンプレ上流の変更を PR として自動取り込み
インストール
cargo install katakata --version で動作確認できれば OK です。
クイックスタート
# 新しい Rust CLI プロジェクトに rust-cli プリセットを適用
mkdir my-rust-cli && cd my-rust-cli
kata init github.com/yukimemi/pj-presets:rust-cli --non-interactive
# テンプレが進化したら再適用 (idempotent)
kata apply --non-interactive
# 適用前のドライラン
kata status
# 何が tracked か確認
kata listこれで Makefile.toml / apm.yml / renri.toml / .github/workflows/ci.yml / release.yml / AGENTS.md / CLAUDE.md / GEMINI.md / rustfmt.toml / clippy.toml / rust-toolchain.toml / renovate.json などがまとめてプロジェクトに落ちてきます。
preset = テンプレートの束
pj-presets:rust-cli は単に「どのテンプレートを、どの順に重ねるか」を書いた小さなファイルです。
# pj-presets/rust-cli.toml
name = "rust-cli"
[[templates]]
source = "github.com/yukimemi/pj-base"
[[templates]]
source = "github.com/yukimemi/pj-rust"
[[templates]]
source = "github.com/yukimemi/pj-rust-cli"順に書かれた順番で適用され、同じファイルが衝突したら後勝ちです。これによって
pj-base— 言語非依存 (LICENSE,.gitignore,AGENTS.mdの共通節,apm.yml,renri.tomlの base,kata-apply.yml……)pj-rust— Rust 共通 (Makefile.toml, CI matrix,rust-toolchain.toml,rustfmt.toml,clippy.toml)pj-rust-cli— CLI 用追加 (release.ymlの cross-compile + cargo publish)
という役割分担ができて、たとえば「Rust ライブラリだから CLI 用 release は要らない」というケースには pj-rust-lib を組み合わせた別 preset を用意するだけで済みます。
ライブラリ向けに rust-lib、Web フロント向けに web-react、Firebase まで含む web-react-firebase も用意していて、preset 単位で気軽に「型」を切り替えられます。
how と when を独立に持つということ
kata の設計でいちばんこだわったのが how (適用方法) と when (タイミング) を別の軸として持つことです。
how |
何をするか |
|---|---|
overwrite |
テンプレ通りにファイルを上書き |
merge-section |
<!-- kata:*:begin --> ~ end の間だけ差し替え |
merge-toml |
toml_edit で指定パスだけマージ |
merge-yaml |
serde_yaml で YAML の指定パスだけマージ |
ai |
claude / gemini / codex に判断委譲 |
script |
任意のシェルコマンドを実行 |
when |
いつ適用するか |
|---|---|
once |
初回だけ。以降は .kata/applied.toml の once_applied = true で skip |
always |
毎回適用 (kata apply のたびに同期) |
manual |
明示的に --file を指定したときだけ |
この 2 軸が独立なので、たとえば
release.ymlはoverwrite, when=once— 初回だけ配って、以降はプロジェクト側で自由に編集ci.ymlはoverwrite, when=always— CI は常に上流追従Makefile.tomlはmerge-toml, when=always— kata 所有のタスクだけ追従AGENTS.mdはmerge-section, when=always— マーカーの中だけ追従apm.ymlはoverwrite, when=once— 初回テンプレ、以降はプロジェクト側LICENSEはoverwrite, when=once— 初回だけ
という細かいポリシーを 1 つの manifest で表現できます。「mode」として 1 つの enum にまとめなかったのは、how="ai", when="once" (ROADMAP.md の初期生成だけ AI に任せる) のような組み合わせを潰したくなかったからです。
AGENTS.md の merge-section が刺さるところ
kata を入れて一番恩恵を感じているのが AGENTS.md の扱いなので、ここは少し詳しく書きます。
pj-base 側の AGENTS.md.base (テンプレ) には共通規約だけが書かれています。
## Shared conventions
This file is the agent-agnostic source of truth (per the
[agents.md](https://agents.md) convention)...
### Git workflow
- **No direct push to `main`.** Open a PR.
- Branch names: `feat/...`, `fix/...`, `chore/...`.
- **PR titles + bodies in English.**
...
### PR review cycle
- Every PR runs reviews from **Gemini Code Assist** and **CodeRabbit**...
- **After opening a PR, immediately enter the review-monitoring loop...**
...
### Worktree workflow
Use [`renri`](https://github.com/yukimemi/renri) for any commit-bound change...これを pj-base/template.toml でこう宣言しています。
[[file]]
src = "AGENTS.md.base"
dst = "AGENTS.md"
how = "merge-section"
when = "always"
marker = { begin = "<!-- kata:agents:base:begin -->", end = "<!-- kata:agents:base:end -->" }kata apply を実行すると、各プロジェクトの AGENTS.md の対応マーカーの中だけがテンプレ内容で置き換わります。マーカーの外にはそのプロジェクトの固有の事情 (アーキテクチャ、設計判断、ドメイン用語、Phase n の状況……) をいくらでも書いておけて、それは kata apply で一切触られません。
さらに layered なので、pj-rust は <!-- kata:agents:rust:* -->、pj-rust-cli は <!-- kata:agents:rust-cli:* --> とそれぞれ自分のマーカーブロックを所有します。これによって 1 枚の AGENTS.md の中に「言語非依存 / Rust 共通 / Rust CLI 専用 / プロジェクト固有」の 4 層が綺麗に同居する、という構造になります。
Makefile.toml の merge-toml で「kata 所有タスク」だけ追従させる
AGENTS.md の marker と並んでよく使うのが、Makefile.toml の merge-toml です。pj-rust/template.toml ではこう宣言しています。
[[file]]
src = "Makefile.toml"
how = "merge-toml"
when = "always"
# kata owns these specific tasks; everything else is left untouched
paths = [
"tasks.default",
"tasks.check",
"tasks.fmt",
"tasks.fmt-check",
"tasks.clippy",
"tasks.test",
"tasks.lock-check",
"tasks.publish-dry",
"tasks.hook-install",
"tasks.apm-install",
"tasks.setup",
"tasks.on-add",
]paths で「kata が所有する TOML のパス」を明示します。tasks.check / tasks.clippy / tasks.test のような kata-managed task は毎回上流から上書きされますが、consumer 側で勝手に追加した tasks.install-local とか tasks.deploy のような独自タスクは paths に含まれないので一切触られない という挙動になります。
merge-toml は toml_edit で paths で指定した key だけを replace していくので、
- 同じ key の値は更新される (例:
tasks.check.scriptの中身が変わる) - paths に出てこない key は consumer の手書きが完全に保持
- インデント / コメント / 順序も
toml_editレベルで保持
という、overwrite だと潰してしまう手書き内容を尊重した同期ができます。
GHA の action バージョンは .kata/vars.toml に切り出して Renovate に任せる
merge-toml × when = "once" のもう 1 つの実用例が、GitHub Actions の version pin を .kata/vars.toml (Tera 変数ファイル) に切り出す パターンです。
考えたい問題はこうです。
ci.yml/release.yml/kata-apply.ymlの version pin (actions/checkout@v6.0.2等) を Renovate に自動 bump させたい- しかし workflow 本体は
overwrite, when=alwaysで kata-managed なので、Renovate が直接ci.ymlを編集しても次のkata applyで潰されてしまう
解決策は、pin だけを .kata/vars.toml に切り出して、workflow 本体は Tera テンプレでそれを参照 することです。
pj-base/vars.toml (universal pin):
[actions]
checkout = "actions/checkout@v6.0.2"
create_pull_request = "peter-evans/create-pull-request@v8.1.1"pj-rust/vars.rust.toml で Rust 専用の pin を追加マージ:
[actions]
swatinem_rust_cache = "Swatinem/rust-cache@v2"template.toml 側で .kata/vars.toml の所有関係を宣言:
# pj-base — universal pin を初回だけ seed
[[file]]
src = "vars.toml"
dst = ".kata/vars.toml"
how = "overwrite"
when = "once"
# pj-rust — Rust 専用 pin を merge-toml で重ねる (初回だけ)
[[file]]
src = "vars.rust.toml"
dst = ".kata/vars.toml"
how = "merge-toml"
when = "once"
paths = ["actions.swatinem_rust_cache"]両方とも when = "once" なので、初回 apply で seed したあとは consumer の .kata/vars.toml を kata は一切触らない、という所有関係になります。ci.yml.tera の中では:
- uses: {{ vars.actions.checkout }}
- uses: {{ vars.actions.swatinem_rust_cache }}として参照されているので、.kata/vars.toml の pin が変われば次の kata apply で ci.yml 全体が新しい version で再レンダリングされる、という流れになります。
その上で consumer 側の .kata/vars.toml を Renovate の customManager が scan していて、新しい action リリースが出たら .kata/vars.toml の pin 値を bump する PR を作ってくれます。Renovate が触るのは .kata/vars.toml の 1 行だけ、workflow 本体は kata-apply の再レンダリングで反映、という分業になります。
まとめると、
- workflow の構造変更 (新ステップ追加、jobs の整理など) → 上流テンプレへの push → daily
kata-applyで降りてくる - action の version bump → consumer の
.kata/vars.tomlを Renovate が自走で書き換える → 次のkata applyでci.ymlが再レンダリング
という、役割分担の明快な並列同期が merge-toml と when = "once" の組み合わせだけで組めます。
ところで、上の ci.yml.tera で {{ vars.actions.checkout }} のように書けているのは Rust 製のテンプレートエンジン Tera のおかげです。.tera サフィックスの付いたファイルが apply 時に Tera で render されて、suffix を落とした名前で consumer に書き出される、というシンプルな仕組み。{% if is_windows() %} のような分岐も {{ env.HOME }} のような環境変数参照も全部 Tera の機能で、kata 側はほぼ何も再発明していません。
実はこの「設定を Tera で書ける」感覚は、rvpm や todoke といった他の Rust 製 CLI でも同じスタックで提供していて、内部では teravars (Tera + vars + include + system context を統一した薄いラッパー) を共有しています。rvpm で見慣れた {% if is_windows() %} がそのまま kata の template でも通る、というのが地味に効いていて、Rust で「設定が宣言的に書ける小さな CLI」を作るときの定番スタックとして teravars はかなりおすすめです。
ここが本題: pj-base を直せば全プロジェクトに反映される
これが kata を作って一番うれしかったところです。
「あ、
AGENTS.mdのこの一節、ちょっと書き方が悪かったな。Claude が誤解しがちだから直したい」 「PR review cycleの節、CodeRabbit の rate-limit notice の扱いを追記したい」 「Worktree workflowの節に新しいrenri pruneの説明を入れたい」
こういう気付きは規約を運用してるとめちゃくちゃ頻繁にあります。kata を入れる前は N 個の AGENTS.md を全部開いて同じ編集を N 回繰り返す ことになっていました。
kata を入れた今はこうなっています。
# pj-base 側でだけ直す
cd ~/src/github.com/yukimemi/pj-base
$EDITOR AGENTS.md.base
git commit -am "docs(agents): clarify PR review cycle"
git push
# あとは何もしなくていい — 翌日になれば、
# kata-apply ワークフローが全 PJ に PR を作って auto-merge する具体的には、各プロジェクトの .github/workflows/kata-apply.yml (これも pj-base 配布) が毎日 03:17 UTC に走って、
- 上流テンプレ (
pj-base/pj-rust/pj-rust-cli) の最新 rev を取得 kata updateで applied.toml の rev を更新kata apply --non-interactive --no-aiで再レンダリング- 差分が出たら
kata-apply/autoブランチに PR を作成 - CI が緑なら auto-merge
を全リポジトリで自動的に回します。規約や設定の更新が該当するテンプレレイヤへの 1 push だけで N プロジェクトに伝播していくわけです。AGENTS.md の共通節なら pj-base、Makefile.toml / rustfmt.toml / clippy.toml / ci.yml といった Rust 共通の規約なら pj-rust、release.yml の cross-compile + cargo publish なら pj-rust-cli、というレイヤ分担そのままに、それぞれの上流に 1 push すれば全 consumer PJ が翌日には追従します。
ワークフロー本体もテンプレ管理なので、ワークフロー自体の改善 (新しい action バージョン、ステップの追加) も同じ仕組みで自動的に各プロジェクトに降りていきます。テンプレが自分自身のメンテも見るかたち。
CI で kata-apply を回す
このフローの肝は CI で kata apply を回せることです。設計時点でここを最優先に考えていて、
--non-interactiveでプロンプトを完全にスキップできる--no-aiで AI ファイルを丸ごとスキップ (= 機械的なテンプレ同期だけ自動で回せる)--non-interactive --yesで「全部 accept」モードもあり (= 信頼できるテンプレなら AI も自動 accept)
という 3 つのフラグで CI 適性が担保されています。
pj-base が配布する kata-apply.yml.tera の中身は essentially こんな感じです (一部抜粋)。
name: kata-apply
on:
schedule:
- cron: "17 3 * * *" # 03:17 UTC daily
workflow_dispatch:
permissions:
contents: write
pull-requests: write
concurrency:
group: kata-apply
cancel-in-progress: false
jobs:
apply:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6.0.2
with:
token: ${{ secrets.KATA_APPLY_TOKEN }} # ← PAT 必須
- name: Install kata
run: |
KATA_VERSION="$(curl -fsSL https://api.github.com/repos/yukimemi/kata/releases/latest | jq -r .tag_name)"
curl -fsSL "https://github.com/yukimemi/kata/releases/download/${KATA_VERSION}/kata-x86_64-unknown-linux-gnu.tar.gz" \
| tar xz -C /tmp
sudo mv /tmp/kata /usr/local/bin/kata
- name: kata update + apply
run: |
kata update
kata apply --non-interactive --no-ai
- name: Open / update PR if there are changes
id: cpr
uses: peter-evans/create-pull-request@v8.1.1
with:
token: ${{ secrets.KATA_APPLY_TOKEN }}
branch: kata-apply/auto
title: "chore(kata): auto-apply"
- name: Enable auto-merge
if: steps.cpr.outputs.pull-request-number != ''
env:
GH_TOKEN: ${{ secrets.KATA_APPLY_TOKEN }}
run: |
gh pr merge --auto --squash ${{ steps.cpr.outputs.pull-request-number }}
要点だけハイライトしておきます。
KATA_APPLY_TOKENはGITHUB_TOKENじゃダメ。GITHUB_TOKEN経由で開いた PR は GitHub のループ防止仕様で下流ワークフロー (CI) を triggers しません。auto-merge の前提が CI 緑判定なので、CI が走らないと永遠にマージされません。適切な権限 (contents: write+pull-requests: write) を付けた PAT (fine-grained でも classic でも可) をKATA_APPLY_TOKENリポジトリシークレットとして設定する、というのが consumer 側の唯一のセットアップ作業です- ブランチは
kata-apply/auto固定。create-pull-requestのdelete-branch: trueと組み合わせると、毎日新しい差分を同じブランチに rolling で上書きしていく動きになるので、PR が大量にスタックしません - CI が落ちたら PR は open のまま残る。auto-merge は CI 緑になったときだけ発火するので、何か壊れたら人間が見るタイミングが自然に生まれます
cron: "17 3 * * *"は意図的な off-peak かつ off-the-hour pin。0 0 * * *や0 9 * * *みたいに :00 ちょうどでスケジュールする人が地球上に多すぎて、GitHub Actions の runner プールが :00 / :30 で枯渇する (cron-storm) という現象があります。:17のような半端な分にずらすと runner 確保がスムーズ。さらに3 UTCは日本時間 12:00 / 米西海岸の夜 / 欧州早朝で、runner 自体も比較的空いている時間帯なので、daily な機械的同期にはちょうどいい枠です
「全プロジェクトに同じワークフローが入っている」という事実が、全プロジェクトに同じ自動同期がかかっている という安心感に繋がっていて、これは入れた価値が大きかったです。
AI 委譲モード
how = "ai" を指定したファイルは、インストール済みの AI CLI に判断を投げます。
template.toml にこう書くと:
[[file]]
src = "ROADMAP.md.tera"
dst = "ROADMAP.md"
how = "ai"
when = "always"
agent = "auto" # claude > codex > gemini で最初に見つかったやつ
prompt = """
Merge the template's structural changes into the project's
ROADMAP.md. Preserve project-specific phases and dated entries.
"""kata は template の diff、現在の dst の中身、prompt をまとめて指定エージェントの CLI (claude -p, gemini -p, codex exec のいずれか) に投げます。返ってきた full body または patch に対して、chezmoi 風の対話プロンプトが出ます。
proposed change for ROADMAP.md:
+ Phase 5 — opencode adapter
+ ## Crate structure (regenerated section)
...
[a]ccept / [e]dit / [s]kip / [d]efer ?a= そのまま採用e=$EDITORで開いて手で直してから採用s= この回はスキップ (次回kata applyでもう一度提案される)d=defer(今回は見送り、ただし「次回必ず再提案」をapplied.tomlに記録)
--non-interactive だけだと安全側に倒れて AI ファイルはスキップ、--non-interactive --yes だと全部 accept という CI 完全自動モードになります。
backend は trait で抽象化されていて、claude / gemini / codex の 3 つを実装済みです。agent = "auto" は PATH を見て上から順にフォールバックしていく挙動。MockAiAgent も組み込まれていて、テストでは決定的な応答が返せます。
並列度の制御もあって、AI 呼び出しはグローバル semaphore (default 4) で絞られます。kata apply --all で 10 個のプロジェクトを並列で回したときに、エージェント CLI の同時起動が爆発しないようにするためです。
.kata/applied.toml が source of truth
kata の状態は全部 PJ 側の .kata/applied.toml に書かれます。グローバル設定 (~/.config/kata/config.toml) は単なる PJ パスのレジストリで、何が適用されているかは知りません。
applied.toml はだいたいこんな感じです。
preset = "github.com/yukimemi/pj-presets:rust-cli"
applied_at = "2026-05-17T04:40:43Z"
[[templates]]
source = "github.com/yukimemi/pj-base"
rev = "f04151faf4f0678be9621bb724c8f3120a5e4d8b"
version = "0.10.0"
[[templates]]
source = "github.com/yukimemi/pj-rust"
rev = "9f103ca5aaf39e1dcf1a4d84b11685821aabc62f"
version = "0.5.0"
[[templates]]
source = "github.com/yukimemi/pj-rust-cli"
rev = "9263751c3f94f3415147e546db33170157fb1503"
version = "0.2.0"
[files."AGENTS.md"]
content_hash = "e4f146a1c66d11e6b6c707f52507b3e37da2fe52d8d7cf13f75edcf9ad5d3a7f"
[files."Makefile.toml"]
content_hash = "27e3f57b9efd6c177843d9b0d248f40af5843739bcde6ceaf985f2ce518ecfcf"
[files."LICENSE"]
once_applied = trueこれを git に commit しておくと、
- teammate が clone →
kata applyで同じ状態が再現できる - CI が
applied.tomlを見るので、ローカル設定なしで CI が完結する - rev が pin されている ので、上流の HEAD が動いても勝手に当たらない (
kata updateで明示的に上げる)
という運用になります。「状態は対象 (PJ) 側に置く、グローバル設定は単なるレジストリに留める」という設計を kata でも採用しました。
kata apply が冪等であること
設計でずっと気をつけたのが「何度走らせても結果が変わらない」ことです。apply が走るたびに差分が出るようなツールは CI で回せないので、
content_hashをapplied.tomlに記録して、変化がないファイルはそもそも書き換えないonce_applied = trueのファイルは 2 回目以降は完全 skipmerge-section/merge-tomlのマージはべき等なように実装 (同じ入力で何度マージしても同じ出力)- AI モードも
--non-interactive --no-aiで完全に固定動作 (= AI モードを除いて再現可能)
という不変条件を守るようにしてあります。
おかげで kata apply --non-interactive --no-ai を毎日 CI で回すと、変更が必要なときだけ PR が立ち、なければ何も起きないという静かな動きになります。
関連プロジェクト
kata の周りに必要な template repo は以下です。すべて単体で意味があるので、好きな組み合わせで preset を組めます。
| repo | 役割 |
|---|---|
pj-base |
言語非依存 (LICENSE, .gitignore, AGENTS.md 共通節, kata-apply ワークフロー, …) |
pj-rust |
Rust 共通 (Makefile.toml, CI matrix, rust-toolchain, rustfmt, clippy) |
pj-rust-cli |
Rust CLI 用 (release.yml の cross-compile + cargo publish) |
pj-rust-lib |
Rust ライブラリ用 (crates.io publish のみ、バイナリなし) |
pj-pnpm |
pnpm / TypeScript 共通 |
pj-react-web |
Vite + React + TS + Tailwind |
pj-firebase |
Firebase Hosting + Firestore |
pj-presets |
rust-cli / rust-lib / web-react / web-react-firebase のバンドル |
kata 自身も dogfood で pj-presets:rust-cli を適用しています — README の表が示す通り、Makefile.toml も CI も AGENTS.md も全部 kata-apply 経由で同期されています。
おわりに
kata を入れる前は、AGENTS.md を 1 行書き換えるのに 7 リポジトリの編集が必要でした。今は pj-base に 1 push すれば、翌日には全プロジェクトに PR が立って auto-merge されています。Claude / Gemini / Codex に渡しているノウハウが全プロジェクトで瞬時に揃う、というのが体験として相当よかったです。
「規約を更新する心理的コストが下がると、規約をもっと細かく洗練させたくなる」というポジティブフィードバックが回り始めていて、Claude Code との PR レビューサイクル運用 (/loop での 60s ポーリング、CodeRabbit の rate-limit notice の扱い、version-bump-only PR の特例……) みたいな細かい知見が、書いた次の日には全 PJ の Claude に届くようになりました。
Rust + Tera + tokio + AI CLI 委譲という shun / rvpm / todoke のときから使い倒している組み合わせに、teravars (Tera engine + vars + include の共通エンジン) を載せた構成で、いつもの定番スタックの延長で書けたのも開発体験として良かったところです。
複数のリポジトリのボイラープレートに疲れている方、特に AGENTS.md などの AI への指示書 を複数プロジェクトに散らかしてしまっている方は、ぜひ kata を試してみてください — 型を押して、版木を当てて、揃えていきましょう。