ターミナルで npm run build && npm run test && npm run deploy のような長いコマンドを毎日打ち込んでいないでしょうか。私は数年間それで通してきましたが、Antigravity の tasks.json と launch.json をきちんと書き始めてから、開発の手応えが明らかに変わりました。Cmd+Shift+B 一発で「保存・リント・ビルド・テスト・問題パネルへの反映」まで連鎖し、AI エージェントから「deploy:staging タスクを実行して」と頼むだけでデプロイが走る環境ができ上がります。
VS Code 由来の設定フォーマットは、ドキュメントが意外と散らばっていて、Antigravity でどう動くのか・AI エージェントとの組み合わせで何ができるのかが分かりにくいです。ここでは私が実際にいくつかのプロジェクトで運用している tasks.json と launch.json を題材に、設計の意図と落とし穴を順に整理していきます。雛形を写経するだけでなく、「なぜそう書くか」を持ち帰っていただければ、自分のスタックに合わせた応用ができるはずです。
tasks.json は「コマンドの語彙」を増やすファイル
tasks.json は .vscode/tasks.json(または .antigravity/tasks.json)に置く JSON ファイルで、エディタから呼び出せるコマンドを宣言的に定義します。シェルスクリプトやパッケージ.json のスクリプトと近い役割ですが、Antigravity のタスクには以下の独自メリットがあります。
- 出力を 問題マッチャー(problem matcher) で解析し、エラーや警告を「問題」パネルに自動転記してくれる
- 別のタスクを
dependsOnでつなぎ、順次実行・並列実行を宣言できる - AI エージェントから
Run task: buildのように呼び出して、結果を会話に取り込める - キーバインドに割り当てて Cmd+Shift+B やカスタムショートカットから一発起動できる
つまり「ターミナル芸」を「エディタの語彙」に昇格させる仕組みです。私はこれを「コマンドの語彙化」と呼んでいて、複数プロジェクトを行き来する個人開発者ほど効いてきます。
最小構成: ビルドタスクを Cmd+Shift+B に割り当てる
まずは Next.js プロジェクトでよくある最小構成を見ていきます。build コマンドを Cmd+Shift+B で呼べるようにする例です。
// .vscode/tasks.json
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"type": "npm",
"script": "build",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "silent", // 成功時はパネルを開かない
"panel": "dedicated", // タスクごとに専用パネル
"clear": true // 実行ごとに前回出力をクリア
},
"problemMatcher": ["$tsc"] // TypeScript の警告・エラーを問題パネルへ
}
]
}期待される動作は、Cmd+Shift+B を押すと npm run build が走り、成功時はパネルが静かに閉じ、失敗時のみ問題パネルにエラーが並ぶというものです。reveal: "silent" を指定すると、ビルドが通っているときに視界を奪われずに済みます。私は通常記事で "reveal": "always" を勧めることが多いのですが、個人開発のように「通って当たり前」のタスクは silent の方が集中を保ちやすいと感じています。
problemMatcher を $tsc にしているのは、TypeScript のコンパイラ出力をパースして問題パネルに転記してくれる組み込みマッチャーだからです。これがあるかないかで、エラー対応の速度がまったく違います。
dependsOn で「準備 → 実行 → 後始末」を1タスクに束ねる
複数タスクをチェインしたいとき、dependsOn と dependsOrder を使うと、シェルスクリプトを書かずに宣言的にまとめられます。私が愛用しているのは「テスト実行の前に prisma generate を必ず走らせる」パターンです。
{
"version": "2.0.0",
"tasks": [
{
"label": "prisma:generate",
"type": "shell",
"command": "npx prisma generate",
"presentation": { "reveal": "silent", "panel": "shared" }
},
{
"label": "test:unit",
"type": "npm",
"script": "test:unit",
"presentation": { "reveal": "always", "panel": "dedicated" },
"problemMatcher": []
},
{
"label": "test (with prisma)",
"dependsOn": ["prisma:generate", "test:unit"],
"dependsOrder": "sequence",
"group": {
"kind": "test",
"isDefault": true
},
"problemMatcher": []
}
]
}dependsOrder: "sequence" で順次実行になります。並列にしたいときは parallel を指定します。group.kind: "test" を isDefault で指定しておけば、Cmd+Shift+P → Tasks: Run Test Task から一発で呼び出せます。
「Prisma を毎回生成するのは無駄では?」と思われるかもしれません。実体験として、CI が通ったのにローカルでテストが落ちる原因の半分くらいは「スキーマ変更後に prisma generate を忘れていた」でした。タスクで強制してしまえば、その種類のバグは消えてくれます。
問題マッチャーを自分で書けると、生のログが資産に変わる
組み込みの $tsc・$eslint-stylish・$go などで足りないとき、problemMatcher を自分で書くことになります。最初は怖いですが、正規表現1〜2本で済むケースが多いので、慣れる価値があります。
Vitest のカラー出力をパースして問題パネルに流す
Vitest を --reporter=verbose で走らせたとき、エラー行は FAIL src/foo.test.ts > should bar のような形になります。これをパースする例です。
{
"label": "test:vitest",
"type": "shell",
"command": "npx vitest run --reporter=verbose",
"problemMatcher": {
"owner": "vitest",
"fileLocation": ["relative", "${workspaceFolder}"],
"pattern": [
{
"regexp": "^\\s*FAIL\\s+(\\S+)\\s+>\\s+(.+)$",
"file": 1,
"message": 2
}
],
"severity": "error"
}
}これだけで、テスト失敗が問題パネルにファイル付きで表示され、クリックで該当行へジャンプできます。
「pattern の正規表現は何度書いてもしっくりこない」というのが正直な感想です。コツとしては、まず command を bash -c "echo 'FAIL src/foo.test.ts > should bar'" のような固定出力に置き換えて、マッチャーが反応するかだけを切り分けることです。コマンドを動かして調整しようとすると、テストの実時間と正規表現の試行錯誤が混ざって混乱します。
マルチライン出力の問題マッチャー
エラーメッセージが複数行にわたる場合、pattern を配列にして「ファイル行 → メッセージ行」を別々にマッチさせます。
"pattern": [
{
"regexp": "^\\s*FAIL\\s+(\\S+)$",
"file": 1
},
{
"regexp": "^\\s*Error: (.+)$",
"message": 1
}
]複数 pattern を書くと、最後の要素が「行を消費するメイン」、それ以前が「文脈を蓄積するサブ」になります。一度書ければあとはコピペで済むので、自社の独自ツールやマイナーなテストランナーでも応用が利きます。
launch.json は「実行とデバッグの台本」
launch.json はデバッガを起動するための設定です。「F5 で何が動くか」を定義する台本だと考えると分かりやすいです。Antigravity でも基本は VS Code と同じですが、AI エージェントから「現在の launch 構成で起動して」のように呼べるのが便利です。
Node.js + TypeScript の最小設定
ts-node や tsx を使った Node.js アプリの最小設定はこのような形になります。
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Run server (tsx watch)",
"type": "node",
"request": "launch",
"runtimeExecutable": "npx",
"runtimeArgs": ["tsx", "watch", "${workspaceFolder}/src/server.ts"],
"console": "integratedTerminal",
"envFile": "${workspaceFolder}/.env.development",
"skipFiles": ["<node_internals>/**", "node_modules/**"]
}
]
}envFile で .env.development を読み込ませているのがポイントです。これを書かずに「環境変数が読まれない」と数時間悩んだことがあります。process.env.X を参照しているコードに対しては、envFile か env のどちらかを必ず指定してください。
skipFiles は「自分のコードでないものを Step Over したい」ときの設定です。<node_internals>/** だけでも体感がかなり変わります。node_modules/** は時々入れたくないこと(依存ライブラリのバグを追いかけているとき)もあるので、プロジェクトごとに切り替えています。
compounds で複数プロセスを同時起動する
Web アプリだとフロントエンドとバックエンドを同時起動したい場面があります。compounds を使うと、複数の configurations を1つの起動構成にまとめられます。
{
"version": "0.2.0",
"configurations": [
{
"name": "Backend",
"type": "node",
"request": "launch",
"runtimeExecutable": "npx",
"runtimeArgs": ["tsx", "watch", "${workspaceFolder}/api/server.ts"],
"envFile": "${workspaceFolder}/.env.development"
},
{
"name": "Frontend",
"type": "node",
"request": "launch",
"runtimeExecutable": "npx",
"runtimeArgs": ["next", "dev"],
"cwd": "${workspaceFolder}/web"
}
],
"compounds": [
{
"name": "Full Stack Dev",
"configurations": ["Backend", "Frontend"],
"stopAll": true
}
]
}stopAll: true を入れておくと、片方を止めたときにもう片方も連動して止まります。これを書き忘れると、フロントを Stop したつもりがバックエンドだけ生き残って、ポート競合の沼にはまります。
実体験として、compounds を導入する前は「フロントを iTerm、バックエンドを Antigravity の Run」のような分業をしていました。導入後は「F5 1発で両方起動・両方デバッガアタッチ」にできるので、起動・停止の認知負荷が激減しました。
AI エージェントからタスクを呼び出す
ここからが Antigravity ならではの強みです。tasks.json に書いたタスクは、AI エージェントから呼び出せます。具体的には、エージェント側のメッセージで Run task: build のように依頼すると、エージェントがタスクを実行し、結果(標準出力・終了コード)を会話に取り込んで次の判断に使います。
「修正 → ビルド → 自動再修正」のループを組む
私が最近よく使うのは、AI エージェントに「TypeScript エラーを修正して、ビルドが通るまで繰り返して」と頼むパターンです。これを破綻なく回すには、タスクの設計が大事になります。
{
"label": "build:strict",
"type": "npm",
"script": "build",
"presentation": { "reveal": "silent" },
"problemMatcher": ["$tsc"],
"options": {
"env": {
"CI": "true"
}
}
}CI=true を渡しているのは、対話的プロンプト(「依存を更新しますか?」など)でビルドが止まらないようにするためです。AI エージェントが裏でビルドを走らせるとき、対話プロンプトに引っかかると永遠に終わらない、という事故を何度か経験しました。
エージェント側のプロンプト例は、私はこのようにシンプルに保っています。
build:strict タスクを実行してください。
失敗したら、エラーを読んで修正し、もう一度実行してください。
3回試して通らなければ、状況を要約して止まってください。
「3回試して通らなければ止まれ」という制限は重要です。これを書かないと、エージェントが延々と無関係な箇所を直し続けて、コードベースが壊れていきます。
デプロイ前にテストとリントを強制する
本番デプロイのタスクは、依存タスクで品質ゲートを必ず通すように書いています。
{
"label": "deploy:cf-pages",
"type": "shell",
"command": "wrangler pages deploy out --project-name=${input:projectName}",
"dependsOn": ["lint", "test:unit", "build"],
"dependsOrder": "sequence",
"presentation": { "reveal": "always", "panel": "dedicated" }
}"inputs": [
{
"id": "projectName",
"type": "promptString",
"description": "Cloudflare Pages のプロジェクト名"
}
]${input:projectName} で実行時にプロンプトが出るので、誤って別プロジェクトへデプロイする事故が起きにくくなります。私は何度か「ステージングのつもりが本番にデプロイ」をやらかして冷や汗をかいたことがあるので、この入力プロンプトは保険として愛用しています。
なお、より重要な決済関連のサービスでは、デプロイ前に手動承認を挟むよう、pickString でロケール(dev / staging / production)を選ばせるパターンもおすすめです。
よくある詰まりどころと対処
ここまでで設計の幹は固まりました。ここからは、私や周囲で実際に詰まったポイントを順に潰していきます。
詰まり 1: 「Cmd+Shift+B が反応しない・違うタスクが走る」
group.isDefault: true を持つタスクが2つ以上あると、Antigravity は「Pick a task」を出すか、最後に追加されたタスクを優先します。意図せず別タスクが走るのは大抵これが原因です。
対処は、isDefault: true を1つに絞るか、明示的に Tasks: Run Build Task から選ぶように運用を変えることです。
詰まり 2: 「launch.json のブレークポイントが赤丸(中抜き)になる」
中抜きの赤丸は、Antigravity が「ソースマップが見つからない」と判断したサインです。原因は大抵以下のどれかです。
- TypeScript の
tsconfig.jsonで"sourceMap": trueを設定し忘れているケース - ts-node ではなく
nodeを直接指定していて、TS をコンパイルしないまま実行しているケース outFilesの指定が現実のビルド出力と合っていないケース
tsx watch を使っている場合は内部でソースマップが解決されるので、outFiles を明示しないほうがむしろ安定します。tsc → node dist/... のように分けている場合は "outFiles": ["${workspaceFolder}/dist/**/*.js"] を必ず書きます。
詰まり 3: 「環境変数が読まれない」
launch.json の env と envFile を両方書くと、env が優先されます。envFile の値を上書きしたくないのに env を書いていて気づかなかった、というケースが意外と多いです。
{
"envFile": "${workspaceFolder}/.env",
"env": {
// ここは「envFile を上書きしたい一時的なフラグ」だけにする
"DEBUG": "app:*"
}
}ベースは envFile に集約し、env は「実行ごとに変えたいフラグ」だけにすると見通しが良くなります。
詰まり 4: 「タスクの shell が PATH を見ていない」
タスクで command: "fly deploy" を書いて「command not found」になることがあります。これは GUI から起動した Antigravity が、ログインシェルの PATH を引き継いでいないのが原因です。
対処は2つあります。
"options": {
"shell": {
"executable": "/bin/zsh",
"args": ["-l", "-c"] // -l でログインシェルを起動
}
}もしくは、command で絶対パスを指定する方法(例: /usr/local/bin/fly deploy)です。私は -l を使うことが多いですが、シェル起動が遅くなるので、頻繁に走らせるタスクでは絶対パス派です。
詰まり 5: 「dependsOn の並列実行で出力が混ざる」
dependsOrder: "parallel" で複数タスクを走らせると、ターミナルの出力が混ざってデバッグできなくなることがあります。presentation.panel: "dedicated" を各タスクに付けると、タスクごとに専用パネルが開いて見通しが良くなります。
"presentation": {
"panel": "dedicated",
"group": "build-parallel" // 同じ group は同じウィンドウにタブ並び
}設定の置き場所と共有戦略
.vscode/ 配下に置くか、.antigravity/ 配下に置くか、迷うところです。私の運用は次のようにしています。
.vscode/tasks.jsonと.vscode/launch.jsonを Git にコミットする(チームで共有したい構成)- マシン固有の設定(API キー、個人の編集設定)は
.vscode/*.local.jsonに分離して.gitignoreに入れる - AI エージェント専用の構成(自動実行系の長いタスク)は
.antigravity/tasks.jsonに分けて、人間用と混ぜないようにしています
最後の点は意外と効きます。「人間が走らせるビルド」と「エージェントに任せる長時間タスク」を同じ tasks.json に書くと、ピッカーが膨れ上がって誤爆しやすくなります。エージェント用は別ファイルに切るのがおすすめです。
個人開発で2週間運用してみて感じたこと
実際に個人プロジェクトで2週間運用してみて、効果を感じたのは次の点です。
- 「同じコマンドをターミナルに打ち込む」時間がほぼゼロになった
- 失敗するタスク(リント・テスト)の結果が問題パネルに集約されるので、エディタを閉じない限り次のアクションが目に入る
- AI エージェントが「ビルドが通らないから直して」と自走するときに、人間が割り込まなくて済む
- 新しいプロジェクトを始めるとき、
tasks.jsonのテンプレートを持ち回ることで、初日から完成度が高い開発環境ができる
逆に、注意点もあります。タスクが多くなりすぎると、Cmd+Shift+P → Tasks のリストから探すのが面倒になります。私は「フリークエントなタスクには keybindings.json でショートカットを割り当てる」ようにして、頻出タスクだけは目を動かさずに走らせています。
// keybindings.json
[
{ "key": "cmd+shift+t", "command": "workbench.action.tasks.runTask", "args": "test (with prisma)" },
{ "key": "cmd+shift+d", "command": "workbench.action.tasks.runTask", "args": "deploy:cf-pages" }
]関連記事
このテーマの周辺を深掘りするには、以下も役立ちます。
- Antigravity のカスタムコマンドを使い倒す
- Antigravity の devcontainer で再現可能な環境を作る
- Antigravity の git worktree で並列ワークスペースを使う
直接 Antigravity の話ではありませんが、「自分の語彙を増やすことが生産性を生む」という視点は共通しています。
tasks.json と launch.json は地味な存在ですが、毎日の繰り返しを 1 行ずつ削っていく効きが大きい場所です。今日いちばん多く打ち込んでいるコマンドを 1 つだけタスクに切り出して、明日からはエディタの中だけで完結させてみてください。半年後の手数の少なさは、きっと驚くはずです。