機密列を含む共有スプレッドシートにAIを安全に書き込ませる型
パスワードや手書きメモと同居する管理表に、AIに本文を読ませずに自動更新させる実装型。許可リスト書込・見出し行の自動検出・行を奪わない突合・列順シャッフルの敵対的テスト・定期実行の引数固定まで。
約3.9万トークンの節約 (API料金換算で約58円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「機密列を含む共有スプレッドシートにAIを安全に書き込ませる型」は、Google WorkspaceカテゴリのAI指示書(MDファイル)です。パスワードや手書きメモと同居する管理表に、AIに本文を読ませずに自動更新させる実装型。許可リスト書込・見出し行の自動検出・行を奪わない突合・列順シャッフルの敵対的テスト・定期実行の引数固定まで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約3.9万トークン(API料金換算で約58円)・92%のトークンを節約できます。
- カテゴリ
- Google Workspace
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約4.2万トークン
- この巻物使用時
- 約3,200トークン
- 節約量
- 約3.9万トークン (約58円)
- 更新日
- 2026-08-28
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/md-45af39d0/raw を読み込んで、この指示書どおりに実装して"
中身
機密列を含む共有スプレッドシートに、AIに本文を読ませずに安全に書き込む
社内の管理表には、AI に自動更新させたい列(機器スペック・稼働状態・最終更新日)と、 絶対に触らせたくない列(パスワード・購入金額・担当者の手書きメモ)が同じシートに同居していることが多い。
素直に「AI にシートを読ませて書き換えさせる」と2つの事故が起きる。
- AI のコンテキストにパスワードが載る(ログ・履歴・外部送信に残る)
- 人が手で書いた列を上書きする(復旧できない)
この2つを構造的に潰す型。AI エージェントにこの MD を読ませればそのまま実装できる。
全体像
各端末のスクリプト --POST--> Apps Script Web App --> スプレッドシート
(値を集めるだけ) (列解決と書き込みを独占)
原則: 端末側にも AI 側にもシートを読ませない。列の解決と書き込みは Apps Script の中だけで行う。 読まなければ漏らせない。
1. 書き込みは許可リスト方式にする(denylist にしない)
禁止列を列挙する方式は、列が増えた瞬間に破綻する。書いてよい列だけを定義する。
// Apps Script 側
var WRITABLE_ = {
maker: 'メーカー', computerName: 'コンピュータ名', cpu: 'CPU',
os: 'OS', memoryGb: 'メモリ容量(GB)', updatedAt: '情報更新日'
};
function normalizeHeader(v) {
// 全角/半角、改行入り見出し、前後空白の差で「見つからない」と誤判定しないため
return String(v == null ? '' : v).normalize('NFKC').replace(/\s+/g, '').toLowerCase();
}
function findHeader(headers, wanted) {
var target = normalizeHeader(wanted);
for (var i = 0; i < headers.length; i++) if (normalizeHeader(headers[i]) === target) return i;
return -1;
}
function planWrite(headers, rows, payload) {
var values = {};
Object.keys(WRITABLE_).forEach(function (key) {
var col = findHeader(headers, WRITABLE_[key]);
var value = payload[key];
// 値が無いときは書かない = 空文字で既存値を潰さない
if (col >= 0 && value !== '' && value != null) values[col] = value;
});
return values;
}
禁止列は WRITABLE_ に載せないというだけで、コードが参照すらしないので構造的に書けない。
2. 「書き込んだ列名」を応答で返す
呼び出し側がシートを読まずに許可リスト遵守を検証できるようにする。これが無いと、 本番で許可リストが守られたかを確認するために結局シートを読むことになる。
var written = [];
Object.keys(values).forEach(function (col) {
sheet.getRange(targetRow, Number(col) + 1).setValue(values[col]);
written.push(headers[Number(col)]);
});
return { ok: true, row: targetRow, written: written };
3. 見出し行だけを返す診断コマンドを用意する
実装には実際の列名の表記が要る(PC No. なのか No なのか、改行が入るのか)。
しかし本文を読むと機密が載る。1行目だけ返す関数を用意して解決する。
function describeHeaders() {
var sheet = targetSheet_();
var found = findHeaderRow_(sheet);
return { headerRow: found.row, headers: found.headers }; // 本文は返さない
}
4. 見出し行が1行目とは限らない
実務のシートは1行目が結合されたタイトル行で、見出しは2行目や3行目にあることが多い。 行1固定で実装すると「必須ヘッダが見つからない」で落ちる。
function findHeaderRow_(sheet) {
var props = PropertiesService.getScriptProperties();
var lastColumn = sheet.getLastColumn();
var cached = Number(props.getProperty('HEADER_ROW') || 0);
if (cached > 0) {
var h = sheet.getRange(cached, 1, 1, lastColumn).getDisplayValues()[0];
if (findHeader(h, WRITABLE_.computerName) >= 0) return { row: cached, headers: h };
props.deleteProperty('HEADER_ROW'); // 構造が変わったらキャッシュを捨てる
}
var scan = Math.min(10, sheet.getLastRow());
for (var row = 1; row <= scan; row++) {
var headers = sheet.getRange(row, 1, 1, lastColumn).getDisplayValues()[0];
if (findHeader(headers, WRITABLE_.computerName) >= 0) {
props.setProperty('HEADER_ROW', String(row));
return { row: row, headers: headers };
}
}
throw new Error('見出し行が先頭' + scan + '行に見つかりません');
}
列レターをハードコードしない。必ず見出し文字列で解決する。 人が列を挿入しても壊れない。
5. 行の突合は「奪わない」規則にする
同じ端末を指す行が、人の手入力行と機械書き込み行に分かれて複数存在するのが普通。
- 第1キー: 機械が書くラベル列の完全一致
- 第2キー: 人が書く名前列の一致 かつ ラベル列が空
- 「名前列は一致するがラベル列に別の名前が入っている行」は絶対に触らない(他人の行を奪う)
さらに 一致した行は全部更新する。最初の1件で打ち切ると、別表記の行が空欄のまま残り、 利用者には「ほとんど書かれていない」ように見える。
突合できなかった項目は既定では行を作らない。明示フラグを付けた時だけ最下部に追記し、 その場合も ラベル列と自動更新列だけ書いて人の入力欄は空のままにする。
6. 敵対的テストで守る(これが本体)
「たまたま今の列順で通った」を排除する。列順をシャッフルして数百回回す。
for (let t = 0; t < 200; t++) {
const headers = shuffle([...FORBIDDEN, ...ALLOWED], t);
const forbidden = new Set(FORBIDDEN.map(h => headers.indexOf(h)));
// 禁止列名をキーに持つ敵対的 payload を投げる
const plan = planWrite(headers, rows, { maker: 'X', 'パスワード': 'p', 'デバイスID': 'd' });
for (const col of Object.keys(plan)) {
assert(!forbidden.has(Number(col)), '禁止列に書き込んだ');
}
assert(plan[headers.indexOf('型番')] === undefined, '空値で既存を上書きした');
}
検証すること:
- 禁止列への書き込みが0件
- 空の値で既存セルを潰さない
- 名前列一致だがラベル列が別名の行を更新しない
- 追記時も人の入力欄が空のまま
7. 定期実行の引数を機械で固定する
新しい収集項目にフラグ(例 --specs)を足したら、定期実行の呼び出し側にも入れる。
入れ忘れると「手で叩いた1台しか記録されない」状態が延々と続き、誰も気付かない。
test('定期ジョブは --specs を渡す', () => {
const line = read('scheduler.mjs').match(/collector\.mjs'[^\n]*/)[0];
assert.match(line, /--specs/);
});
このテストはわざとフラグを外して落ちることまで確認する(落ちないテストは無いのと同じ)。
8. 黙って成功しない
書き込み系のコマンドは、成功時にも 更新件数・書き込んだ列・突合できなかった対象を必ず出力する。
何も出さないと「届いていない」ことに誰も気付けない。例外を握り潰す catch {} は置かない。
つまずきやすい実装上の罠
| 症状 | 原因 | 対処 |
|---|---|---|
| 値が全部空になる | 生のオブジェクトを JSON 化してメタデータごと数百KBになり、値が取り出せない | 直列化の前に必要なプロパティだけ選ぶ |
must be a string without null bytes | パス中の \0 がテンプレートリテラルで NUL 文字になる | \\0 と書く |
| 見出しに一致しない | 見出しに改行や全角が混じる | NFKC 正規化+空白除去で照合 |
| 端末情報が文字化け | 日本語 OS のコマンド出力が別のエンコーディング | 出力を UTF-8 に固定し、さらに数値だけ抜く正規化関数を通す |
| 容量が実際の半分以下 | 32bit 幅のフィールドが上限で飽和している | 64bit の別ソースを優先し、飽和値なら書かない |
| 「無し」と誤って記録される | 接続中のものしか列挙しない API を「存在しない」証拠に使っている | あり / なし / 判定不能 の3値にし、断定できない側は判定不能 |
認証について
新しい鍵を増やさない。Web App 側に共有トークンを1つ持たせ、端末はそれを送るだけにする。 トークンの投入は、Drive にコマンドファイルを置いて時間トリガーで処理させる方式にすると 人の手作業がゼロになる(結果もファイルで返る)。
よくある質問
+「機密列を含む共有スプレッドシートにAIを安全に書き込ませる型」とは何ですか?
パスワードや手書きメモと同居する管理表に、AIに本文を読ませずに自動更新させる実装型。許可リスト書込・見出し行の自動検出・行を奪わない突合・列順シャッフルの敵対的テスト・定期実行の引数固定まで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約4.2万トークンかかりますが、この巻物を使えば約3,200トークンで済みます。差し引き約3.9万トークン(API料金換算で約58円)・92%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
GAS完全自動化テンプレ — Driveコマンドキュー方式
Google Apps Script の「毎回エディタで▶実行」を根絶。Drive 経由のコマンドキューで、初回1クリック以降は AI がすべての GAS 関数をリモート実行できるようになるテンプレート指示書。
人間の手入力台帳を壊さずに自動更新する — GAS Web App upsert 設計
各PC/各拠点の点検結果を、人間が手運用しているスプレッドシート台帳へ自動反映する。手入力列とコメントを絶対に壊さない突合設計、タブ/列の解決、並行POST対策、配布シークレットの落とし穴まで。
数式まみれの業務スプレッドシートを、Webアプリから壊さずに編集させる型
ArrayFormula と per-row 数式が混在する台帳を、セル単位 allowlist・dry-run 既定・適用前バックアップ・触っていないセルの数式不変検査で安全に書き換える設計手順。列ごとの数式復元と、テストが緑のまま壊れる典型例つき。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア