appscript について
appscript は、clasp を使ってターミナルから Google Apps Script プロジェクトを開発・管理するスキルです。ローカル編集からテスト、デプロイまでを扱い、プロジェクト構成やデバッグも案内します。
主な機能
- 01スクリプトのローカル編集とプッシュ
- 02バインド型・スタンドアロン型の複製と管理
- 03関数のリモート実行とログ確認
- 04デプロイバージョンの作成と管理
- 05TypeScript をコンパイルしてからプッシュ
活用シーン
- 01ターミナルから Google Apps Script プロジェクトを保守
- 02関数をテストして実行ログを調査
- 03Web App、API Executable、Add-on のデプロイ
MCP 対応
ドキュメントでは、clasp を MCP サーバーとして使い、Claude Code から Google Apps Script プロジェクトを直接管理する方法を説明しています。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ smkeramati/ appscript --skill appscriptインストール後、Claude Code で/appscriptを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdLICENSE.gitignoreTODO.mdappscript-workspace/iteration-1/benchmark.jsonappscript-workspace/iteration-1/eval-1-weekly-email/eval_metadata.jsonappscript-workspace/iteration-1/eval-1-weekly-email/with_skill/timing.jsongrading.jsonappscript-workspace/iteration-1/eval-1-weekly-email/with_skill/outputs/response.mdmetrics.jsonappscript-workspace/iteration-1/eval-1-weekly-email/without_skill/grading.jsontiming.jsonappscript-workspace/iteration-1/eval-1-weekly-email/without_skill/outputs/metrics.jsonresponse.mdappscript-workspace/iteration-1/eval-2-webhook-app/eval_metadata.jsonappscript-workspace/iteration-1/eval-2-webhook-app/with_skill/timing.jsongrading.jsonappscript-workspace/iteration-1/eval-2-webhook-app/with_skill/outputs/metrics.jsonresponse.mdappscript-workspace/iteration-1/eval-2-webhook-app/without_skill/grading.jsontiming.jsonappscript-workspace/iteration-1/eval-2-webhook-app/without_skill/outputs/metrics.jsonresponse.mdappscript-workspace/iteration-1/eval-3-timeout-fix/eval_metadata.jsonappscript-workspace/iteration-1/eval-3-timeout-fix/with_skill/timing.jsongrading.jsonappscript-workspace/iteration-1/eval-3-timeout-fix/with_skill/outputs/response.mdappscript-workspace/iteration-1/eval-3-timeout-fix/without_skill/timing.jsonappscript-workspace/iteration-1/eval-3-timeout-fix/without_skill/outputs/metrics.jsonresponse.md詳細
appscript — clasp による Google Apps Script
ターミナルから Google Apps Script プロジェクトを開発、編集、デプロイできます。作成/クローン → ローカルで編集 → プッシュ → テスト → デプロイという、ライフサイクル全体をカバーします。ブラウザーでのコピー&ペーストは不要です。
クイックスタート
# Verify clasp is installed (needs Node 22+)
clasp --version
npm install -g @google/clasp # install if missing
# One-time: enable Apps Script API in your Google account
# https://script.google.com/home/usersettings → toggle ON
# Without this, every clasp command fails with an authorization error.
clasp login # authenticate (opens browser)
clasp create-script --title "My Script" # start a new standalone project
# — or —
clasp clone-script <scriptId> # clone existing project
# scriptId: script.google.com → gear icon → Script ID
.gs ファイルをローカルで編集してから、clasp push を実行します。これが基本の作業サイクルです。
スクリプトの種類:バインド型とスタンドアロン型
この違いは、作成、クローン、データへのアクセス方法に関わるため重要です。
スタンドアロンスクリプト — script.google.com または clasp create-script を使って作成します。Drive 内で独立して動作します。明示的な ID を指定して Google サービスにアクセスします(例:SpreadsheetApp.openById('...'))。
コンテナバインド型スクリプト — シート、ドキュメント、フォーム、スライドの内部から「拡張機能 → Apps Script」を選択して作成します。親ファイルと密接に連携します。GAS はスクリプトがどのファイルに属するかを認識しているため、引数なしで SpreadsheetApp.getActiveSpreadsheet() を呼び出せます。onEdit(e) などのトリガーが機能するのはバインド型スクリプトのみです。
バインド型スクリプトをローカルで使用する方法:
- シート/ドキュメントを開く → 拡張機能 → Apps Script
- 歯車アイコン(プロジェクトの設定)→ スクリプト ID をコピー
clasp clone-script <scriptId>— これでローカルファイルを取得できます
主な動作上の違い:
// Bound script — works without an ID
const ss = SpreadsheetApp.getActiveSpreadsheet();
// Standalone script — must supply the ID
const ss = SpreadsheetApp.openById('1BxSheet...');
プロジェクト構成
my-project/
├── .clasp.json ← project config (scriptId, rootDir)
├── .claspignore ← gitignore-style exclusions from push
├── appsscript.json ← manifest (must exist and be pushed)
├── Code.gs ← main logic
├── Utils.gs ← helpers
└── ui.html ← HTML for web apps / sidebars
すべての .gs ファイルはグローバルスコープを共有します。モジュールや import/export はありません。Utils.gs で定義した関数は、Code.gs から自動的に利用できます。トップレベルの宣言ではファイルの読み込み順序が重要です。必要に応じて .clasp.json の filePushOrder で制御してください。
appsscript.json では、必ず V8 ランタイムを使用してください。V8 では ES6 以降の機能(アロー関数、async/await 構文、分割代入)が使えます。使用しない場合は、ES5 の Rhino で動作します。
{
"timeZone": "America/New_York",
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8"
}
日常のワークフロー
clasp show-file-status # preview what will push/pull (dry run)
clasp push # upload local → Google
clasp push --watch # auto-push on every file save
clasp push --force # skip confirmation prompts
clasp pull # download Google → local
clasp pull --versionNumber 3 # pull a specific version
実行とデバッグ
# Execute a function remotely
clasp run-function myFunction
clasp run-function processData --params '["arg1", 42]'
# Stream Cloud Logging
clasp tail-logs
clasp tail-logs --watch # continuous
clasp tail-logs --json # machine-readable
# Debug clasp itself
DEBUG=clasp:* clasp push
clasp run-function を実行するには、プロジェクトをAPI 実行可能ファイルとしてデプロイするか、Apps Script API を有効にした GCP プロジェクトをリンクする必要があります。この設定がない場合は、script.google.com の Apps Script エディタから直接プッシュしてテストするか、リンクされたシートからトリガーしてください。
バージョンとデプロイ
バージョンは変更できないスナップショットです。デプロイはバージョンを参照し、スクリプトを外部に公開します。
clasp create-deployment --description "v1.0 initial release"
clasp create-deployment --versionNumber 3 --description "hotfix"
clasp list-deployments
clasp update-deployment <deploymentId> --versionNumber 4 --description "v1.1"
clasp delete-deployment <deploymentId>
clasp delete-deployment --all
デプロイの種類(appsscript.json で設定):
- ウェブアプリ —
doGet(e)/doPost(e)が必要です。公開 URL からアクセスできます - API 実行可能ファイル — 外部の呼び出し元から
clasp run-functionを実行できるようにします - アドオン — Google Workspace Marketplace で配布できます
認証
clasp login # standard OAuth (opens browser)
clasp show-authorized-user # confirm active account
clasp logout
# Multiple accounts
clasp login --user work
clasp login --user personal
clasp push --user work # specify per command
# CI/CD (no browser)
clasp login --adc # uses GOOGLE_APPLICATION_CREDENTIALS
clasp login --creds client_secret.json # org GCP project OAuth
API の管理
clasp enable-api sheets # enable Sheets API for this project
clasp list-apis # see available and enabled APIs
clasp disable-api drive
TypeScript
Clasp v3 では、組み込みの TypeScript トランスパイル機能が削除されました。推奨される方法は、外部でコンパイルしてから出力をプッシュすることです。
セットアップ:
npm install --save-dev typescript rollup @rollup/plugin-typescript @types/google-apps-script
rollup.config.js:
import typescript from '@rollup/plugin-typescript';
export default {
input: 'src/index.ts',
output: { file: 'dist/Code.js', format: 'esm' },
plugins: [typescript()]
};
.clasp.json — コンパイル済み出力を rootDir に指定します:
{ "scriptId": "...", "rootDir": "dist/" }
ビルドしてプッシュします:
npx rollup -c && clasp push
TypeScript を使わずに型ヒントを利用する — VS Code の自動補完のために型定義をインストールします:
npm install --save-dev @types/google-apps-script
GAS ライブラリ
ライブラリを使うと、ファイルをコピーせずに GAS プロジェクト間でコードを共有できます。
ライブラリの使用方法:
- 作成者からライブラリのスクリプト ID を入手します
appsscript.jsonに追加します:
{
"dependencies": {
"libraries": [
{
"userSymbol": "MyLib",
"libraryId": "1T03atLib...",
"version": "3"
}
]
}
}
- コード内で
MyLib.functionName()としてアクセスします
ライブラリの作成方法:
- 通常どおりスクリプトを作成します
- 「ライブラリ」タイプとしてデプロイします(スクリプトエディタで、デプロイ → 新しいデプロイ → ライブラリ)
- スクリプト ID を利用者と共有します。新しいデプロイのたびに、利用者はバージョン番号を追加します
注:GAS が実行時にライブラリを解決するため、ライブラリを使うと関数呼び出しごとに約 50 ミリ秒のオーバーヘッドが発生します。パフォーマンスが重要なホットパスでは、代わりにコードをインライン化してください。
GAS のコード品質
Sheets の操作をまとめて実行する
Google サービス(Sheets、Drive、Gmail など)を呼び出すたびに、約 100~500ms の HTTP ラウンドトリップが発生します。ループ内で 100 個のセルを個別に読み取ると、100 回のリクエストが順番に実行され、6 分の実行タイムアウトに達することもよくあります。読み取りと書き込みはまとめて実行してください。
❌ API 呼び出し 100 回 — 遅く、タイムアウトのリスクがあります:
for (let i = 1; i <= 100; i++) {
const val = sheet.getRange(i, 1).getValue();
sheet.getRange(i, 2).setValue(val * 2);
}
✅ API 呼び出し 2 回 — 高速です:
const vals = sheet.getRange('A1:A100').getValues(); // one read
const result = vals.map(([v]) => [v * 2]);
sheet.getRange('B1:B100').setValues(result); // one write
SpreadsheetApp.flush(); // commit buffered writes before any subsequent read
GAS は書き込みをバッファリングするため、SpreadsheetApp.flush() が必要です。これを省略すると、書き込み直後の読み取りで古いデータが返されることがあります。
言語の制限
// ✅ Works in V8
const fn = (x) => x * 2;
const [a, ...rest] = array;
// ⚠️ async/await syntax works in V8, BUT GAS has no event loop
// Only use it if you have a real native Promise to await.
// setTimeout, setInterval, and browser I/O never fire — there's no scheduler.
async function example() {
const result = await someNativePromise; // ok
// await fetch(...) — won't work, use UrlFetchApp.fetch() instead
}
// ❌ Never works in GAS (any runtime)
import { foo } from './utils.js' // no ES modules — global scope only
export default function() {}
fetch('https://api.example.com') // use UrlFetchApp.fetch() instead
setTimeout(() => {}, 1000) // no timer callbacks
window / document / localStorage // no DOM or browser APIs
// ❌ V8 parse error — avoid
class Foo { #privateField = 1; } // private class fields not supported
PropertiesService に設定を保存する
.gs ファイルに API キーや設定をハードコードすると、Google にプッシュされ、スクリプト編集者から見える状態になります。代わりに PropertiesService に保存してください。デプロイ間で保持され、ソースファイルにも含まれません。
// Write once (e.g., a setup function)
PropertiesService.getScriptProperties().setProperty('API_KEY', 'your-secret');
// Read anywhere
const key = PropertiesService.getScriptProperties().getProperty('API_KEY');
よくあるパターン
ウェブアプリ(HTTP ハンドラー):
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('ui').setTitle('My App');
}
function doPost(e) {
const data = JSON.parse(e.postData.contents);
// process...
return ContentService.createTextOutput(JSON.stringify({ ok: true }))
.setMimeType(ContentService.MimeType.JSON);
}
時間ベースのトリガー:
function setupTrigger() {
ScriptApp.newTrigger('myFunction').timeBased().everyHours(1).create();
}
// To remove all triggers:
ScriptApp.getProjectTriggers().forEach(t => ScriptApp.deleteTrigger(t));
外部 HTTP リクエスト:
const res = UrlFetchApp.fetch('https://api.example.com/data', {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ key: 'value' }),
headers: { Authorization: 'Bearer ' + token }
});
const json = JSON.parse(res.getContentText());
コストの高いフェッチをキャッシュする(最大 6 時間):
const cache = CacheService.getScriptCache();
let data = cache.get('mykey');
if (!data) {
data = JSON.stringify(UrlFetchApp.fetch('https://api.example.com').getContentText());
cache.put('mykey', data, 1500); // 25 minutes
}
return JSON.parse(data);
スリープによるレート制限対策:
// When hitting APIs that throttle (e.g. UrlFetch returning 429)
items.forEach((item, i) => {
processItem(item);
if (i % 10 === 9) Utilities.sleep(1000); // pause 1s every 10 calls
});
Gemini AI(Ai サービス経由 — GAS ネイティブ):
// Available in GAS without any API key setup — uses project's linked GCP
function summarizeText(text) {
const model = Ai.getGenerativeModel({ model: 'gemini-2.0-flash' });
const result = model.generateContent(text);
return result.response.text();
}
注:Ai サービスを使用するには、Vertex AI または Generative Language API が有効になっている GCP プロジェクトをリンクする必要があります。または、独自の API キーを使って UrlFetchApp.fetch() 経由で Gemini REST API を呼び出してください。
トラブルシューティング
| エラー | 原因 | 対処方法 |
|---|---|---|
Apps Script API has not been used | アカウントで API が有効になっていません | https://script.google.com/home/usersettings → 有効にする |
Could not find .clasp.json | プロジェクトのルートにいません | プロジェクトディレクトリに cd します |
Authorization required | マニフェストで OAuth スコープが変更されています | 再度プッシュし、スクリプトエディタで再認証します |
Script timeout | 6 分の実行制限を超えています | 小さなバッチに分割し、トリガー経由で連鎖させます |
Service using too much computer time | 1 日あたりの割り当て上限に達しています | バッチ操作を使用し、24 時間待ちます。Workspace アカウントでは上限が高くなります |
| 書き込み後に古いデータが表示される | 書き込みがバッファリングされています | 読み取りの前に SpreadsheetApp.flush() を呼び出します |
| プッシュ確認のループ | 対話型ターミナルのプロンプトです | --force フラグを追加します |
| アップグレード後にコマンドが見つからない | Clasp v2 → v3 で名前が変更されました | references/clasp-commands.md の名称変更表を参照してください |
HttpResponseException: 429 | UrlFetch のレート制限に達しています | 呼び出しの間に Utilities.sleep(1000) を追加し、リクエストをまとめます |
ReferenceError: X is not defined | ファイルの読み込み順序に問題があります | .clasp.json に filePushOrder を追加します |
MCP / AI 統合
clasp を MCP サーバーとして使用すると、Claude Code から GAS プロジェクトを直接管理できます。
claude mcp add clasp -- npx -y @google/clasp mcp
# Or in Claude Code:
# /plugin install @google/clasp
参考ファイル
必要に応じて読み込んでください。詳細が必要でない限り、事前に読み込まないでください。
| ファイル | 読み込むタイミング |
|---|---|
references/clasp-commands.md | 任意のコマンドのフラグをすべて確認する場合、または clasp v2 から移行する場合(名称変更表がすべて記載されています) |
references/gas-reference.md | 1 日あたりの割り当て、利用可能なすべてのサービス、デプロイマニフェストのフィールド、その他のコードパターン、トリガーの種類を確認する場合 |
references/config-files.md | .clasp.json / appsscript.json / .claspignore のフィールドをすべて確認する場合 |