ANTIGRAVITY LABEN
記事一覧/アプリ開発
アプリ開発/2026-09-10初級

iOS 27 の配信日が決まってから、私が最初に grep したのは AGENTS.md でした

iOS 27 と iPadOS 27 の配信は9月14日です。版数の文字列はソースだけでなく、エージェントが読む設定ファイルにも残ります。両方を数えるスクリプトと、keyword 検索では拾えない一行の話を書き残します。

antigravity455ios272agents98app-dev52

9月14日、という日付をしばらく眺めておりました。iOS 27 と iPadOS 27 の配信日です。対応は iPhone 11 以降。手元のカレンダーで数えると、あと四日でした。

個人開発でアプリを出しておりますと、この四日間の使い方で秋の忙しさがずいぶん変わります。以前の私は、まずソースコードを開いておりました。@available の分岐を数え、デプロイメントターゲットを確かめ、実機ごとの場合分けを見直すところまでを、毎年の手順にしておりました。そこまでやれば準備は済んだつもりでいたのです。

結果は芳しくありませんでした。配信の翌週、エージェントに書かせた新しい画面のコードに、また古い可用性の分岐が入っていたのです。私が直し忘れていたわけではありません。直した場所と、エージェントが読んでいた場所が違っていたのでした。

版数の文字列は、二つのゾーンに散らばっています

版数がリポジトリに文字列として残る場所は、性質の違う二つに分かれます。

ゾーン読むものファイルの例間違いに気づく仕組み
A人間とコンパイラ.swift / .h / .xcconfig / .plist / build.gradleビルド警告・コードレビュー・CI
BエージェントAGENTS.md / rules.json / agents.json / skills.json / .antigravity/ 配下ありません

右端の列が要点です。ゾーン A の古い版数はコンパイラが教えてくれます。ゾーン B の古い版数は、誰も教えてくれません。文章として正しく、構文としても壊れていないからです。ただ、そこに書いてある前提のとおりにコードが生成されるだけなのです。

しかもゾーン B は増える方向にあります。Antigravity 2.11.0 で、プロジェクトのサブディレクトリに置いた skills.json / agents.json / rules.json も探索の対象に入りました。あわせて AGENTS.md とカスタムルールファイルの中で @path/to/file 記法が使えるようになり、外部のファイルをその場に展開できます。さらに 2.12.2 では、Markdown で定義したカスタムエージェントが周囲のスキル・ルール・サブエージェントを既定で継承するようになりました。

つまり、リポジトリの根元にある AGENTS.md だけを見て「確認しました」と言える状態では、もうないのです。

二つのゾーンを別々に数えます

そこで、配信日が決まった日に走らせる棚卸しのスクリプトを用意しました。ゾーンを分けて数えることだけを目的にしています。

#!/usr/bin/env bash
# os-literals.sh — 古い OS 版数がリポジトリのどこに文字列として残っているかを数えます。
# 使い方: bash os-literals.sh <リポジトリのパス> <古い版数> [新しい版数]
#   例:   bash os-literals.sh . 26 27
set -uo pipefail
 
ROOT="${1:-.}"; OLD="${2:?古い版数を指定してください(例: 26}"; NEW="${3:-}"
 
# 版数の直前に来る語だけを拾います。単独の "26" は年号にも座標にも当たるためです。
PAT="(iOS|iPadOS|macOS|watchOS|tvOS|visionOS|Xcode|SDK|DEPLOYMENT_TARGET|available)[^0-9A-Za-z]{0,12}${OLD}([.][0-9]+)?"
 
list_a() {  # 人間とコンパイラが読むもの
  find "$ROOT" -type f \( -name '*.swift' -o -name '*.h' -o -name '*.m' -o -name '*.kt' \
    -o -name '*.xcconfig' -o -name '*.plist' -o -name '*.gradle' -o -name '*.pbxproj' \) \
    -not -path '*/.git/*' -not -path '*/node_modules/*' -print0 2>/dev/null
}
 
list_b() {  # エージェントだけが読むもの
  find "$ROOT" -type f \( -name 'AGENTS.md' -o -name '*.agent.md' -o -name 'skills.json' \
    -o -name 'agents.json' -o -name 'rules.json' -o -name '.antigravityrules' \
    -o -path '*/.antigravity/*' \) \
    -not -path '*/.git/*' -not -path '*/node_modules/*' -print0 2>/dev/null
}
 
report() {  # report <ラベル> <ファイル列挙関数>
  local label="$1" hits n
  hits=$("$2" | xargs -0 -r grep -InE "$PAT" 2>/dev/null)
  n=$(printf '%s' "$hits" | grep -c . )
  printf '%s: %d 件\n' "$label" "$n"
  [ "$n" -gt 0 ] && printf '%s\n' "$hits" | sed "s|^${ROOT}/||; s/^/    /"
  return 0
}
 
echo "== ゾーン A: 人間とコンパイラが読むもの =="
report "ソース・ビルド設定" list_a
echo
echo "== ゾーン B: エージェントだけが読むもの =="
report "エージェント設定" list_b
 
echo
echo "== @ 記法で取り込まれている参照先 =="
list_b | xargs -0 -r grep -hoE '@[A-Za-z0-9_./-]+\.(md|json|ya?ml)' 2>/dev/null \
  | sed 's/^@//' | sort -u | while read -r ref; do
      if [ -f "$ROOT/$ref" ]; then
        c=$(grep -cE "$PAT" "$ROOT/$ref" 2>/dev/null || true)
        printf '    %-40s %s 件\n' "$ref" "${c:-0}"
      else
        printf '    %-40s 参照先が見つかりません\n' "$ref"
      fi
    done

小さな検証用のリポジトリで走らせた出力が、こちらです。

$ bash os-literals.sh ./fixture 26 27
== ゾーン A: 人間とコンパイラが読むもの ==
ソース・ビルド設定: 2 件
    ios/Config/Base.xcconfig:1:IPHONEOS_DEPLOYMENT_TARGET = 26.0
    src/Views/HomeView.swift:4:    if #available(iOS 26.0, *) { Text("new") } else { Text("old") }
 
== ゾーン B: エージェントだけが読むもの ==
エージェント設定: 3 件
    packages/mobile/rules.json:1:{ "rules": ["Assume Xcode 26 toolchain", "minimum iOS 26.0"] }
    .antigravity/rules/swiftui.md:1:Prefer the iOS 26 glass material APIs.
    AGENTS.md:3:Target platform: iOS 26 and later. Use `@available(iOS 26, *)` when adding new APIs.
 
== @ 記法で取り込まれている参照先 ==
    .antigravity/rules/swiftui.md            1 件

ゾーン B のほうが件数が多いことが分かります。私が最初にこの分け方で数えたとき、素直に肩の力が抜けました。直すべき場所は多いのですが、どこを見ればよいかがはっきりしたからです。

最後の節も見落とせません。.antigravity/rules/swiftui.mdAGENTS.md から @ 記法で取り込まれているファイルです。ルールを分割して整理している方ほど、根元のファイルだけを開いて安心してしまいます。取り込み先を辿る一手間が要ります。

keyword では拾えない一行が残ります

この棚卸しには、あえて拾わないようにしている行があります。iOSXcode のような語を伴わない、裸の版数です。

// ios/Config/DefineManager.h
#define kMinOS 26.0

26.0 だけを検索の対象にすると、座標や年号や無関係な定数まで一緒に釣れてしまいます。ですから第一のパスでは外し、目視前提の第二のパスとして分けて走らせています。

# 第二のパス。件数は少なく、そのぶん一件ずつ目で見ます。
grep -rnE '(^|[^0-9A-Za-z.])26\.0([^0-9]|$)' . \
  --include='*.h' --include='*.xcconfig' --include='*.json'

これを分けたのは、一度に全部を拾おうとして失敗したからです。最初のうち、私は網を広げすぎておりました。出力が数百行になり、目が滑り、結局どれも直さないまま配信日を迎えてしまったのです。いまは「keyword つきは機械が、裸の数値は自分が」という分け方に落ち着いております。

そのうえで、書き手として引いた線がもうひとつあります。版数は、それが何の版数かを示す語と並べて書いておきます。 #define kMinOS 26.0 ではなく #define kMinOS_iOS 26.0 と書いてあれば、来年の私も、エージェントも、一度の検索で見つけられます。検索できる形で書き残すことは、それ自体が保守なのだと感じています。

直す順番は、影響の大きい側から

件数が出たあとの順番も決めてあります。

  1. ゾーン B のうち @ で取り込まれているファイル — 展開されて複数のエージェントに効くため、一箇所の修正で効き目がいちばん広く届きます
  2. ゾーン B の残りAGENTS.md・各 rules.json)— 継承が既定になった以上、狭い文脈のつもりで書いたルールも周囲へ伝わります
  3. ゾーン A のビルド設定.xcconfig.plist。ここはビルドが教えてくれるので、慌てなくても大丈夫です
  4. ゾーン A の可用性分岐 — 数が多いぶん時間がかかります。新しい版が降りてから、実機の挙動を見つつ順に

ゾーン B を先に直すのは、ここを放っておくとゾーン A の修正が上書きされていくからです。古い前提の残ったルールを読んだエージェントは、せっかく直した分岐を、次の生成でまた古い形に戻してしまいます。

なお、審査側の準備は別立てで進めておくと楽になります。2026年9月から、新規提出・アップデート・代替配信向けの公証申請のいずれにも年齢レーティングの質問票への回答が必要になりました。この答えをリポジトリ側の宣言から組み立てる方法は、年齢レーティングの質問票に、記憶ではなくリポジトリの宣言で答えるに書きました。配信直後は提出が混み合いますので、四日のうちに済ませておくと呼吸が楽になります。アプリ側の初期化と権利の復元についてはiOS 27 の RC から正式リリースまでの5日間のほうにまとめてあります。

四日のうちに、一度だけ走らせてください

今日できることは一つだけで足ります。手元のリポジトリで os-literals.sh を一度走らせ、ゾーン B の件数を見てください。ゼロならそのまま配信日を迎えられますし、一件でもあれば、そこがあなたのエージェントの読んでいる前提です。

私自身、この棚卸しを始めてから、新しい OS が降りてくる週の胃の痛みがだいぶ減りました。準備が完璧になったからではありません。どこを見ていないかが分かっているという、それだけの違いなのです。お読みいただきありがとうございました。

シェア

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

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

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

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

アプリ開発2026-09-04
iOS 27 の RC から正式リリースまでの5日間 — 画面より先に、初期化の順番と権利の復元を確かめます
OS が入れ替わる直前の短い窓で、エージェントに渡す検証範囲を画面まわりではなく起動経路で切るまでの記録です。ATT と広告 SDK の順序、権利の復元、寸法のハードコード分岐を機械で洗い出す監査スクリプトを添えています。
アプリ開発2026-08-15
壁紙アプリの30カテゴリ分類で、エージェントに選ばせる範囲をどこまで狭めるか
画像を見せて30個のカテゴリから選ばせる分類バッチは、定義を1つ足すだけで全件やり直しになります。エージェントには閉じた語彙のタグだけを出させ、カテゴリは決定的な規則で写像する設計へ切り替えた判断と実装を共有します。
アプリ開発2026-08-24
消えたのは中身ではなく作業ディレクトリでした — 無人で走る破壊操作を fail-closed に組み直す
無人で走らせていた掃除処理が、掃除対象の中身ではなく作業ディレクトリそのものを消しました。mkdir -p が安全弁にならなかった理由と、取得失敗を既定値で埋める書き方が破壊側の分岐を選んでいた経緯を、実際の検証出力とともに整理します。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます