早朝に走るはずだった処理が、翌朝に見に行っても何ひとつ残していない——そんな朝を、私は何度か迎えております。エラーの通知すら届いておらず、手元には昨日と同じ中身のディレクトリだけが残っておりました。
Antigravity 2.0 の Scheduled Tasks は、cron 式を書いておけば予定時刻にコマンドやエージェントの呼び出しが自動で始まる仕組みです。チャットからであれば /schedule "0 9 * * 1-5" 週次のPRレビュー状況をまとめてください のように一行で登録できます。書くのは拍子抜けするほど簡単なのですが、無人で走る仕組みには共通の弱点があります——うまくいかなかったとき、画面の前に誰もいないのです。
最初にお伝えしたいのは、切り分けの順番です。設定の中身を疑う前に、そもそも起動したのかどうかを先に確かめます。ここを飛ばしますと、正しい設定を何度も書き直すという遠回りになります。
「動かなかった」には二つの状態があります
一つめは、そもそもプロセスが起動していない状態です。二つめは、起動したけれども何も出力せずに終わった状態です。結果だけを見ますと両者は見分けがつきませんが、原因はまったく別のところにあります。
前者の原因は、ほぼ設定側にあります。置き場所、ID、そして有効化の三点です。後者はスクリプト側の問題で、権限や作業ディレクトリ、環境変数の食い違いが多くを占めます。
私は最初のうち、この二つを区別しないまま設定ファイルばかり直しておりました。結果は芳しくありませんでした。実際には毎回きちんと起動していて、スクリプトが最初の一行で落ちていただけだったのです。
sidecar.json は、置いたディレクトリ名がそのまま ID になります
Scheduled Tasks の実体は、sidecar と呼ばれる背後のプロセスです。Antigravity が起動と再起動の面倒をみます。設定は sidecar.json を探索して見つけられ、置き場所は二か所です。
- グローバル:
~/.gemini/config/sidecars/<名前>/sidecar.json - プラグイン:
~/.gemini/config/plugins/<プラグイン名>/sidecars/<名前>/sidecar.json
ディレクトリ名が、そのまま sidecar の ID になります。プラグイン側は <プラグイン名>/<名前> という形です。ここを覚えておきませんと、次に出てくる有効化の設定でつまずきます。
もう一つ見落としやすいのが、その sidecar のディレクトリがコマンドの作業ディレクトリになることです。おかげでスクリプトは相対パスで指定できますが、参照先のリポジトリまで相対で書いていますと、走った先で見つかりません。
| キー | 型 | 役割 |
|---|---|---|
command | string | 実行するコマンド。builtin とは排他 |
builtin | string | 組み込み処理。現状は schedule のみ |
args | string[] | 引数。schedule では先頭が cron 式 |
restart_policy | string | always / on-failure / never(既定は always) |
env | object | プロセスに渡す環境変数 |
display_name | string | UI 上の表示名。ID ではありません |
毎朝5時に手元のスクリプトを走らせる場合は、次のようになります。
{
"display_name": "Morning asset sync",
"description": "壁紙アプリ用の素材を早朝に取り込みます",
"builtin": "schedule",
"args": ["0 5 * * *", "/bin/bash", "run.sh"],
"restart_policy": "always"
}builtin に schedule を選んだときは、args の先頭が5フィールドの cron 式で、残りが実行するコマンドと引数になります。command と builtin は排他ですので、両方書くことはできません。
restart_policy の既定値は always です。スケジューラ自体は常駐していてほしいので既定のままで構いませんが、一度きり動けば済む処理を command で登録する場合は、never や on-failure を自分で選ぶようにしております。
enabled を書くまで、設定が正しくても一度も起動しません
ここが最初の関門でした。sidecar は、ユーザーが明示的に有効化するまで無効のままです。 ~/.gemini/config/config.json に次のように書きます。
{
"sidecars": {
"morning-asset-sync": { "enabled": true },
"my-plugin/review-triage": { "enabled": true, "projectId": "YOUR_PROJECT_ID" }
}
}キーは先ほどの ID、つまりディレクトリ名です。私はここでディレクトリ名と display_name を取り違え、半日ほど溶かしました。表示名は UI のためのもので、有効化の照合には使われません。
projectId は、sidecar から agentapi new-conversation でエージェントの会話を作る場合に必要です。コマンドを叩くだけの用途であれば要りません。
ログとイベントは sidecar_data の下に落ちます
起動したかどうかを確かめる場所は決まっております。~/.gemini/antigravity/sidecar_data/<sidecarId>/ の下に、次の三つが作られます。
logs/— 標準出力と標準エラーが、時刻つきのファイルで残りますevents/—agentapiの呼び出しが JSON で記録されますdata/— 永続データの置き場で、ANTIGRAVITY_EXECUTABLE_DATA_DIRから参照できます
切り分けはここで終わります。logs/ に当日のファイルがあれば、起動そのものはしております。ファイルすらなければ、疑うべきは enabled と ID です。
ls -lt ~/.gemini/antigravity/sidecar_data/morning-asset-sync/logs/ | head -5走った証拠は、成功したときではなく走り始めた時点で書きます
私が長らく間違えていたのは、ここでした。成功したときだけログを残す作りにしていたのです。走ったのに何も出力しなかった日と、そもそも起動しなかった日を、翌朝の私は区別できませんでした。いま思えば、成功だけを記録していたのは、うまくいく前提で仕組みを組んでいたからかもしれません。
いまは、成功・スキップ・失敗のどれかを必ず一行残す形にしております。走った証拠は、成功したときではなく走り始めた時点で書きます。 この線引きだけは、急いでいる日でも崩さないようにしております。
#!/bin/bash
set -uo pipefail
LOG_DIR="${ANTIGRAVITY_EXECUTABLE_DATA_DIR:-$HOME/.local/share/agy-jobs}"
mkdir -p "$LOG_DIR"
STAMP="$(date +%Y-%m-%dT%H:%M:%S%z)"
LOG="$LOG_DIR/$(date +%Y-%m-%d).log"
echo "$STAMP START asset-sync" >> "$LOG"
if [ ! -d "$HOME/material/incoming" ]; then
echo "$STAMP SKIP incoming ディレクトリが無いため何もしません" >> "$LOG"
exit 0
fi
if python3 sync_assets.py >> "$LOG" 2>&1; then
echo "$STAMP OK asset-sync" >> "$LOG"
else
echo "$STAMP FAIL exit=$? asset-sync" >> "$LOG"
exit 1
fiこの形にしておく理由は、読み返すときにはっきりします。START の行があるのに OK も FAIL も無い日は、途中で止められたか、再起動を繰り返した疑いがあります。START すら無い日は、そもそも起動していません。三つの状態を持たせておきますと、翌朝どこを読めばよいかが一目で決まります。
もう一つ、私の環境で実測した注意を添えます。複数の時刻をカンマで並べた cron 式(30 4,16 * * * のような書き方)が、片方の時刻でしか発火しなかったことがあります。 これは Antigravity ではなく、私が普段使っている別のスケジューラでの出来事です。それでも、1日に2回動かしたい処理は枠ごとに別のタスクへ分ける、という運用に切り替えてから取りこぼしはなくなりました。カンマ区切りに頼る前に、一度だけ実測しておく価値はあります。
明日の一歩
まずは、毎分 date を書き出すだけの sidecar を一つ作ってみてください。args に ["* * * * *", "/bin/bash", "-c", "date >> heartbeat.log"] と置き、config.json で有効化して、logs/ にファイルが増えていくのを見届けます。ここまで通れば、あとは中身を差し替えるだけです。
無人実行を運用へ載せますと、次に効いてくるのは「走らなかった回」をどう検知するかという設計です。実行台帳と期待表の突合まで踏み込んだ話は、エージェントの定期実行で、失敗より先に「走らなかった」を疑うようになりましたに書き残しております。
最後までお読みくださり、ありがとうございました。皆さまの夜間の処理が、翌朝きちんと足跡を残していますように。