◉ANTIGRAVITY LABEN
記事一覧/連携・プラグイン
⬡ 連携・プラグイン/2026-06-21上級

Antigravity CLI の JSON Lines 出力を自作スクリプトで受ける — 部分行と終了コードでつまずいた記録

Antigravity CLI の機械可読出力(JSON Lines)を自前スクリプトに流し込むと、3回に1回ほど JSONDecodeError で止まりました。部分行・終了コード・stderr 混入という3つの罠と、行バッファリングで安定させた実運用の受け口を記録します。

antigravity472cli7automation55jsonpipeline4

✦ プレミアム記事

Antigravity CLI(agy)の出力を別のスクリプトに流し込んで、品質チェックを通してから次の処理へ渡す——という小さなパイプラインを組んだとき、最初の数日は3回に1回ほど json.JSONDecodeError: Expecting value で止まっていました。エージェント自体は正常に走っているのに、その出力を受ける側が壊れる。原因はエージェントでもモデルでもなく、私自身の「出力の受け取り方」にありました。

CLI を対話的に眺めている分には気づきません。出力を機械で受け始めて初めて表に出る問題です。同じところでつまずく方は少なくないと思うので、何が起きていたのか、どう直したのかを順に残しておきます。

機械可読出力は「行」が単位、でも行は途中で届く

Antigravity CLI は、人が読むための整形出力とは別に、機械可読なイベント列を出力できます。バージョンによってフラグ名は異なりますが(agy --help で確認してください)、多くは1行=1イベントの JSON Lines(NDJSON)形式です。agent_started、tool_call、agent_completed のようなイベントが、エージェントの進行に合わせて1行ずつ流れてきます。

ここで最初の誤解がありました。「1行=1 JSON なら、受け取った塊を改行で割って json.loads すればいい」と考えたのです。バッチでまとめて受けるならそれで動きます。問題は、進捗をリアルタイムで見たくてストリーミングで読み始めた瞬間に起きました。

パイプやストリームは「行」という単位を保証してくれません。read(4096) のように固定長で読むと、ちょうど行の途中でぶつ切りになった塊が返ってきます。次の read で残りが届くまで、その行は不完全なままです。私が最初に書いたのは、まさにこの前提を踏み外したコードでした。

import json
import subprocess
 
proc = subprocess.Popen(
    ["agy", "run", "--json", "task.md"],
    stdout=subprocess.PIPE,
    text=True,
)
 
# ❌ 1回の read で「行が途中まで」しか来ないことがある
while True:
    chunk = proc.stdout.read(4096)
    if not chunk:
        break
    for line in chunk.split("\n"):
        event = json.loads(line)  # 部分行・空行で JSONDecodeError
        handle(event)

chunk.split("\n") の最後の要素は、たいてい次のチャンクの先頭と繋がるべき「行の前半分」です。それを単独で json.loads に渡せば当然壊れます。空行(末尾の改行が生む空文字列)でも同じく落ちます。エラーは確率的に出るので、最初は「モデルがたまに変な出力をする」と疑ってしまい、本当の原因にたどり着くまで遠回りしました。

いちばん簡単で正しい受け口は「1行ずつ反復する」

Python のテキストモードのストリームは、for line in stream: で反復すると行の完結を保証してくれます。ぶつ切りの心配をしたくなければ、まずこの形に寄せるのが最短です。あわせて、行バッファリング(bufsize=1)と stderr の分離も最初から入れておきます。

import json
import subprocess
import sys
 
 
def consume(cmd):
    """Antigravity CLI の JSON Lines 出力を1行ずつ安全に受ける。"""
    proc = subprocess.Popen(
        cmd,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,  # 進捗ログを stdout に混ぜない
        text=True,
        bufsize=1,               # 行バッファリング
    )
 
    events = []
    for raw in proc.stdout:      # 1行ずつ・行は必ず完結している
        line = raw.strip()
        if not line:             # 空行はスキップ
            continue
        try:
            events.append(json.loads(line))
        except json.JSONDecodeError:
            # JSON でない行(起動バナー等)が紛れても、握りつぶさず記録だけ残す
            sys.stderr.write(f"skip non-json line: {line[:120]}\n")
 
    code = proc.wait()
    return code, events

for raw in proc.stdout: が肝です。これだけで部分行の問題は消えます。行で読めない事情がない限り、私はまずこの形を推奨します。strip() で前後の空白と改行を落とし、空行を弾き、JSON でない行は捨てつつ標準エラーに記録します。ここで例外を握りつぶして pass だけにすると、後で「なぜか一部のイベントが落ちている」という別の沼にはまります。捨てるにしても、捨てた事実は残す。これは自分への戒めです。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦CLI の機械可読出力をパイプで受けたときに行が途中で切れて JSON パースが壊れる問題を、行バッファリングと残余の持ち越しで安定させられるようになります
✦エージェントの成否を「最後の1行」ではなく終了コードと完了イベントの両方で判定する、二重ゲートの設計を自分の自動化に組み込めるようになります
✦stdout(データ)と stderr(進捗ログ)の分離・タイムアウト・実行ごとの一時ディレクトリまで含めた、無人運用に耐える受け口の雛形を手元に持てるようになります
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

⬡ 連携・プラグイン2026-11-03
スプレッドシートの手作業を Apps Script に置き換える——非エンジニアが Antigravity に出す最初の依頼
毎週のコピー&貼り付けを Apps Script に任せたい非エンジニア向けに、Antigravity への依頼文、消さない設計、ドライラン、トリガー設定、つまずく所の切り分けまでを一本の流れでまとめます。
⬡ 連携・プラグイン2026-10-17
Antigravity のブラウザエージェントがログイン画面で止まるときに確認する4点
ブラウザエージェントに管理画面を読ませたら、返ってきたのはサインイン画面だけ。別 Chrome プロファイルという仕様を踏まえ、ログイン状態を整える4つの確認点をまとめました。
⬡ 連携・プラグイン2026-09-05
GOOGLE_GEMINI_BASE_URL を差し替えても、鍵の持ち主は変わりません
Antigravity CLI の宛先を自前のゲートウェイへ向けたとき、手元の API キーがどこまで運ばれるかを受け側で記録しました。クロスホストのリダイレクトで Authorization は落ちるのに API キーヘッダーは残る、という挙動差の実測と、鍵を端末から外すゲートウェイの組み方を書き残します。