mcpField
C
cheez-write

cheez-write

github.com/paulnsorensen開発19158 回インストール6 日前に更新
リポジトリ

cheez-write について

cheez-write は、追跡対象のソースコードを古い状態で上書きしないよう、アンカー付きバックエンドで変更するコーディングスキルです。現在の内容を先に読み、範囲を限定して編集するか、意味的・構造的な変更を適切なツールに振り分けます。

主な機能

  1. 01編集内容に応じたバックエンド選択
  2. 02行・ブロック単位のアンカー編集
  3. 03古いタグの検出と復旧
  4. 04複数・複数ファイルの編集
  5. 05意味的リファクタリングとコード変換の振り分け

活用シーン

  1. 01既知の関数本体を安全に置換
  2. 02複数ファイルへ編集を適用
  3. 03読み取り後にファイルが変わった場合の復旧
  4. 04シンボル名変更を LSP に振り分け

MCP 対応

tilth MCP の tilth_write ツールを使い、ファイルタグと行番号に結び付いた編集を行う方法を説明します。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/paulnsorensen/easy-cheese --skill cheez-write

インストール後、Claude Code で/cheez-writeを入力して読み込まれたか確認します。

同梱ファイルreferences/edit-patterns.mdreferences/routing.md

詳細

cheez-write

バックエンドの要件:古い状態に安全な編集バックエンドを使用してください。バックエンドは現在のファイル状態(tilth ファイルタグ、スナップショットタグ、または LSP ワークスペース編集)を基準にする必要があります。または、クリーンなツリーに対する意図的な AST コードモッドである必要があります。

バックエンドの検出

編集の形状に基づいてバックエンドを選択し、基本的なハーネス編集ツールよりもコードインテリジェンスバックエンド(LSP、AST リライト、tilth)を優先してください。モデルのチューニングはホストの Edit/Write を選びがちですが、これらには意味的・構造的な認識機能がありません。

  1. 意味的なワークスペース編集では LSP を優先: サーバーがシンボルや修正箇所を特定できる場合の名前変更/コードアクション。
  2. 構造的なコードモッドでは AST リライトを優先: メタ変数を含む、繰り返し現れる構文パターン。まずドライランを実行してください。
  3. アンカー付きブロック/範囲編集では tilth MCP を優先: tilth_read が [path#TAG] ヘッダーを出力し、その後 tilth_write が edits: [{path, tag, ops}] を介して行番号付き操作を適用します。
  4. 表示されたスナップショットにはネイティブのアンカー付き編集(フォールバック): 古い範囲を拒否する行/スナップショット編集です。編集の形状に合うコードインテリジェンスバックエンドがない場合に限ります。

sed、awk、patch、シェルのリダイレクト、または無条件の書き込みを、同等のソースコード編集として提示しないでください。

古いタグや拒否されたセクションはコンテンツの問題です。古いタグの処理を参照してください。


例

「src/auth.ts の handleAuth の本体を置き換える」

手順 1 — 行範囲を読み取り、ファイルタグを取得します。

tilth_read(paths: ["src/auth.ts#44-89"])
# returns a [src/auth.ts#b2c4] header, then numbered lines 44:... to 89:...

手順 2 — これらの行番号に対して操作を適用し、タグをそのまま引用します。

tilth_write(edits: [{
  "path": "src/auth.ts",
  "tag": "b2c4",
  "ops": [{
    "op": "replace",
    "start": 44,
    "end": 89,
    "content": "export function handleAuth(req, res, next) {\n  const token = extractToken(req);\n  if (!validateToken(token)) return res.status(401).end();\n  next();\n}"
  }]
}])

応答には ## src/auth.ts ごとの結果が報告され、確認が必要な呼び出し元が一覧表示される場合があります。

「古いタグ — ファイルが変更されています」

復旧手順については、古いタグの処理を参照してください。


基本原則:書き換えではなくアンカー

編集バックエンドは、tilth ファイルタグ、ハーネスのスナップショットタグ、または LSP ワークスペース編集によって現在のファイル状態を特定し、ファイルが変更されていた場合は書き込みを制限または拒否する必要があります。

プロトコル:

  1. cheez-read でファイルのセクションを読み取る → 現在の [path#TAG] ヘッダーまたはスナップショット ID を取得する
  2. 変更するブロックの行番号を確認する
  3. アンカー付きバックエンドを介して編集を適用する

対象範囲:アンカー付き編集を使う場合、使わない場合

cheez-write は、追跡対象のソースコードに対するブロック編集(関数本体、シグネチャ、インポート、単一行の微調整、複数編集の一括処理、ファイルをまたぐ変更)を担当します。バックエンドは古い状態に安全である必要があり、重要なコード変更には読み取りと編集のプロトコルが必須です。

それ以外には、適切なツールを優先してください。

変更代わりに使用するもの理由
複数ファイルにまたがる横断的な構造コードモッド(JSON.parse(JSON.stringify($X)) → structuredClone($X))sg --rewrite(## 構造コードモッド — sg --rewrite による代替を参照)コードモッドでは変数部分をテンプレート化します。アンカー付き編集は、対象のブロックが既知の場合に適しています
意味的な名前変更またはサーバーが把握しているリファクタリングLSP の名前変更/コードアクションLSP はスコープ、オーバーロード、再エクスポート、インポートを追跡します
ロックファイルの変更(Cargo.lock、package-lock.json、uv.lock など)パッケージマネージャー(cargo update、npm i、uv lock)ロックファイルを手動編集するとチェックサムの整合性が損なわれます
生成物/ビルド成果物(コンパイル済み JS、トランスパイルされた出力、*.pb.go)ソースから再生成する成果物を編集しても、次のビルドで古くなります
新規ファイル(既存の内容がないもの)アンカー付き作成/書き込みバックエンド(tilth:tag を省略した tilth_write セクション)ファイルの作成時も古い状態に安全な方法を維持できます
リポジトリ外、または依存関係キャッシュ内(node_modules、.cargo/registry)のファイル編集しない依存関係を変更するのはほとんどの場合誤りです。ソースまたは上流を修正してください
バイナリファイル、画像、PDF生成元のツールコード編集バックエンドはテキスト専用です

LSP の名前変更または Serena へのルーティング

事前ルーティング(ワークフロースキルが cheez-write に入る前に tilth_write より LSP の名前変更または Serena のシンボル範囲編集を優先すべき場合)については、references/routing.mdを参照してください。


アンカー形式

選択したバックエンドが出力するアンカー形式を使用してください。

  • tilth:N:content 形式の番号付き行の上に [path#TAG] ヘッダーが表示されます。4 桁の 16 進数の TAG を tilth_write の tag にコピーし、ops では該当する行番号を指定してください。TAG を決して作り出さないでください(mode: "stripped" の読み取りには TAG がなく、編集に再利用できません)。
  • OMP スタイルのスナップショット編集:[file#TAG] と表示された行番号を指定します。タグと元の行範囲を編集ツールに渡してください。
  • LSP リファクタリング:シンボルの位置とワークスペースのバージョンを指定します。ワークスペース編集の作成はサーバーに任せてください。

アンカー方式を相互に変換しないでください。書き込みに使用するバックエンドと同じファミリーで読み取ってください。


MCP ツールリファレンス

tilth_write — ファイルの精密編集

最小構成は、1 つのファイルセクションと 1 つの op です。

tilth_write(edits: [{
  "path": "src/auth.ts",
  "tag": "a3f9",
  "ops": [
    { "op": "replace", "start": 42, "end": 42, "content": "  let x = recompute();" }
  ]
}])

edits は {path, tag?, ops} セクションオブジェクトの JSON 配列です(1 回の呼び出しにつき最大 20 個)。文字列にしたり、files パラメーターでラップしたりしないでください。各 op は op でタグ付けされます。replace {start, end, content}、delete {start, end}、insert_before / insert_after {line, content}、prepend / append {content}、replace_block / insert_after_block {at, content} および delete_block {at}(at は行番号または "#symbol")、delete_file、move_file {dest} を指定できます。新規ファイルを作成する場合に限り、tag を省略します。

各 op の使用例、複数ファイルにまたがる一括編集、および diff: true レスポンスオプションについては、 references/edit-patterns.md を参照してください。


古いタグの処理

TAG は、読み取った内容に op を結び付けます。読み取り後にファイルが変更されている場合、tilth は op を変更後のファイルに対して 3 者マージします。安全にマージできない場合は、そのセクションを拒否し、## <path> ごとの結果にその旨を示します。

復旧手順:

  1. セクションをもう一度読み取り、現在の [path#TAG] と内容を取得します。
  2. 現在の内容を確認します(ほかの人が変更を加えている可能性があります)。
  3. 新しいタグを使用し、最新の行番号に対して op を再適用します。
拒否が繰り返される場合 → ループせず中断する

同じファイルに対して2 回連続で拒否された場合は、同時に書き込むほかの処理と競合しています。「タグを無視して、この文字列に一致させる」オーバーライドはありません。3 回目の再試行でも同じ競合が起きる可能性が高いです。

適切な対応は、作業を中断して次のように報告することです。

  1. 最新のセクションを最後にもう一度読み取り、現在の内容を取得します。
  2. 統合差分またはブロック全体として新しい内容を準備しますが、適用しないでください。
  3. 取得したタグと提案する内容を添えて、"tag race on <path>; current content and proposed replacement attached. Retry once the file is quiescent or apply manually." と報告します。
  4. 停止します。変更を適用するか、エスカレーションするかは、オーケストレーター(または人間)に委ねてください。

シグネチャ変更後の呼び出し元の更新

シグネチャを変更する場合は、完了前に LSP の参照または編集バックエンドの呼び出し元通知を使用してください。呼び出し箇所を見落とすとバグになります。


よくあるパターン

目的リファレンス
1 行を置換するedit-patterns.md#single-line-replacement
範囲を置換するedit-patterns.md#multi-line-range-replacement
ブロックを削除するedit-patterns.md#delete-a-block
行の前後に挿入するedit-patterns.md#insert-before-or-after-a-line
シンボル全体を置換/削除するedit-patterns.md#symbol-anchored-block-ops
1 つのファイルで複数の編集を行うedit-patterns.md#multiple-edits-in-one-file
複数ファイルにまたがる変更edit-patterns.md#edits-across-multiple-files

ファイル全体の書き換えが許容される場合

アンカーを使ったピンポイントの編集がデフォルトです。選択したバックエンドが古いスナップショットを引き続き拒否し、ファイルが十分に小さく、行単位の編集を積み重ねるより置き換えたほうがレビューしやすい場合に限り、ファイル全体の書き換えが許容されます。

ファイルサイズ方針
> 150 行ファイル全体を書き換えることは絶対にしないでください。必ずアンカー付きブロック編集を使用してください。
≤ 150 行アンカー付きの単一編集を優先しますが、ファイルの80%以上が変更される場合は、全体の書き換えも許容されます。このしきい値未満の場合は、ピンポイントで編集してください。

150 行/80%のしきい値は、2026 年のデータ(Cursor、can.ac、Morph ベンチマーク)に基づいています。小さなファイルでは、全体の書き換えは diff 形式と同等か、それを上回ります。一方、大きなファイルでは常にアンカー付き編集を使用します。

小さなファイルであっても、アンカーなしのホスト Write に切り替えないでください。サイズによって古い書き込みのリスクがなくなるわけではありません。


構造的なコード変換 — sg --rewrite の例外

アンカー付き編集では既知のブロックを編集し、各箇所でアンカーを取得するために 1 回読み取ります。周囲のテキストが一定でない横断的な構造コード変換(「すべての JSON.parse(JSON.stringify($X)) を structuredClone($X) に書き換える」など)には、Bash 経由で sg --rewrite(ast-grep)を使用してください。これにより、メタ変数を使って変数部分をテンプレート化できます。ハッシュアンカーによる安全性はないため、コード変換ごとに、クリーンな Git の状態間で 1 回のトランザクションとして実行してください。メタ変数の構文と、必須のドライラン優先プロトコルについては、../cheez-search/references/sg-patterns.mdを参照してください。


禁止事項

  • タグを作り出さないでください — 必ず最初に読み取り、[path#TAG] ヘッダーをそのままコピーしてください。
  • 拒否されたセクションを無視しないでください — 再度読み取り、再試行してください(「古いタグの処理」を参照)。
  • コードの編集に sed / awk / perl -i を使用しないでください — アンカーと構造上の安全性を迂回し、不一致の検出もできません。シェルを使用する例外として許可されているのは sg --rewrite のみです。「## 構造的なコード変換 — sg --rewrite の例外」を参照してください。
  • コードに diff を適用するために patch を使用しないでください — アンカー付き範囲編集が安全な代替手段です。
  • コードファイルの上書き/追記に tee やシェルのリダイレクト(>、>>)を使用しないでください — いずれもアンカーを迂回します。アンカー付き編集バックエンドを使用してください。
  • アンカーなしのホスト Edit/Write ツールを使用しないでください — tilth_write、ハーネス標準のアンカー付き編集、または LSP ワークスペース編集を使用してください。
  • 単発のブロック編集に sg --rewrite を使用しないでください — アンカー付き編集を使用してください。コード変換の例外を適用できる場合については、「## 構造的なコード変換 — sg --rewrite の例外」を参照してください。
  • sg --rewrite でドライラン優先プロトコルを省略しないでください — 「## 構造的なコード変換 — sg --rewrite の例外」を参照してください。
  • 読み取りなしで編集しないでください — アンカーは読み取りの手順で取得します。
  • このスキルからテストの実行、コミット、公開、レビューを行わないでください — プロジェクトのテスト/ビルドゲートを使用し、コミット/公開には /plate、レビューには /age を使用してください。
  • 読み取りや検索に使用しないでください — /cheez-read で読み取り、/cheez-search で検索してください。

コメント