金曜の朝、GitHub の Issue を一つ読み終えたところで手が止まりました。
「iPhone から送った指示が、ターンが終わるまで Claude に届かない」という報告です。私自身、Mac で長めの作業を任せて席を外し、スマホから「そこは後回しで」と一言だけ送ることがよくあります。あの一言が、実は作業の終わりまで箱の中で待っていたのだとしたら——訂正のつもりが、ただの事後報告になってしまいます。
ここからは、症状の見分け方、原因の切り分け順、止めずに届ける方法、直らないときの次の一手を順にお伝えします。報告者の計測と、私が手元で書いて動かした確認用スクリプトをもとにしています。
まず症状を見分ける — 入力欄の文言が合図です
いちばん早い見分け方は、iPhone の Claude アプリの入力欄に出ている薄い文字を見ることです。
| 状態 | 入力欄の表示 | 送ったメッセージの行き先 |
|---|---|---|
| Claude が待機中 | Type / for commands | すぐに渡る |
| Claude が作業中 | Queue for after this turn… | ターンが終わるまで保留される |
作業中に送ったメッセージが複数あると、ターンの終わりにまとめて一通として渡ります。「三回に分けて送ったのに、返事が一回分の内容をまとめて受けたものになっている」と感じたら、この症状を疑ってよいと思います。
エラーはどこにも出ません。だからこそ気づきにくく、「Claude が訂正を無視した」と受け取ってしまいがちなのです。
原因の切り分け — 版の境目は 2.1.321
報告者(Issue #108975)は、デスクトップアプリに同梱される Claude Code の版だけを入れ替えて比べています。条件は「5 秒のツール呼び出しを続けさせ、その間に iPhone から送る」です。
| Claude Code の版 | 作業中に iPhone から送ったメッセージ |
|---|---|
| 2.1.309 | 次のツール結果のところで渡った(3/3) |
| 2.1.319 | 次のツール結果のところで渡った(4/4、再試行で 8/8) |
| 2.1.321 | ターン終了まで保留(7/7) |
| 2.1.322 | ターン終了まで保留(7/7) |
報告者によれば、2.1.321 には「Queue for later で送った Remote Control のメッセージが、実行中のターンの途中で Claude に届いてしまう」不具合の修正が入っています。修正そのものは正しいのです。問題は、iPhone アプリが作業中のメッセージをすべて「後回し」として送っており、デスクトップのような「今すぐ送る」の選択肢を持っていないことでした。
切り分けは次の順で進めると迷いません。
- 送った端末が iPhone(または iPad)アプリかを確かめます。ターミナルや Mac アプリからの送信は対象外です
- 入力欄が「Queue for after this turn…」になっていたかを思い出します
- Mac の Claude Desktop が動かしている Claude Code の版を確かめます。2.1.321 以降なら該当します
- 同じ症状がターミナルや Mac アプリからの送信でも起きるなら、別の原因を探します
なお、ターミナルでは入力したメッセージが実行中のツール呼び出しのあとに入り、Mac アプリでは保留中のメッセージに「Send now」が付いていると報告されています。届かないのは、いまのところ iPhone からの送信だけです。
本当に保留されていたかを数える
「遅れた気がする」で終わらせず、記録で確かめておくと、Issue に追記するときも自分で判断するときも足場になります。Claude Code のセッション記録(通常は ~/.claude/projects/ 配下の .jsonl)には、作業中に送ったメッセージの出入りが queue-operation という行で残ります。
次のスクリプトは、送った時刻と Claude が受け取った時刻を突き合わせ、まとめて渡ったものに印を付けます。
#!/usr/bin/env python3
"""セッション記録(.jsonl)から、送ったメッセージが Claude に渡るまでの待ち時間を数える"""
import json
import sys
from collections import Counter
from datetime import datetime
from pathlib import Path
def parse_ts(value):
# 末尾の Z は Python 3.10 以前の fromisoformat が読めないので置き換える
return datetime.fromisoformat(value.replace("Z", "+00:00"))
def load_queue_events(path):
events = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
row = json.loads(line)
except json.JSONDecodeError:
continue # 書きかけの最終行などは飛ばす
if row.get("type") != "queue-operation":
continue
ts, op = row.get("timestamp"), row.get("operation")
if ts and op:
events.append((parse_ts(ts), op))
return sorted(events)
def main():
if len(sys.argv) != 2:
sys.exit("usage: queue_wait.py <session.jsonl>")
events = load_queue_events(Path(sys.argv[1]).expanduser())
if not events:
print("queue-operation の記録がありません(作業中の送信が無いか、記録の形式が違います)")
return
waiting, delivered = [], []
for ts, op in events:
if op == "enqueue":
waiting.append(ts)
elif op == "dequeue" and waiting:
delivered.append((waiting.pop(0), ts)) # 先に送ったものから渡る前提
elif op == "popAll":
delivered += [(sent, ts) for sent in waiting]
waiting = []
# remove は通知などが途中で取り込まれた記録で、人の送信ではないので数えない
batch = Counter(got for _, got in delivered)
print(f"{'送信':<10} {'受け取り':<10} {'待ち(秒)':>8}")
for sent, got in delivered:
wait = (got - sent).total_seconds()
mark = f" ← {batch[got]} 件まとめて渡った" if batch[got] > 1 else ""
print(f"{sent:%H:%M:%S} {got:%H:%M:%S} {wait:8.0f}{mark}")
if waiting:
print(f"\nまだ渡っていないメッセージ: {len(waiting)} 件")
if __name__ == "__main__":
main()python3 queue_wait.py ~/.claude/projects/<フォルダ>/<セッションID>.jsonl のように渡します。報告にある時刻の並びを手元で再現した記録に通すと、7〜13 秒待った 3 件が「3 件まとめて渡った」と表示されました。
ここで書き残しておきたいのは、待ち時間の長さより、まとめて渡ったかどうかを見るということです。短いツール呼び出しが続いた場合、保留されていても数秒で届くことがあります。秒数だけで判断すると見逃しますが、同じ時刻に複数がまとめて渡っていれば、それはターンの終わりまで待っていた跡です。記録の形式は版によって変わる可能性があるため、queue-operation が一件も見つからないときは、その旨を表示して終わるようにしています。
止めずに届けるための回避策
公式の修正が出るまでのあいだ、私が選ぶ順番は次のとおりです。
- Mac が近くにあるなら、デスクトップで「Send now」を押します。保留中のメッセージを今すぐ扱いに切り替えられます
- ブラウザの claude.ai から同じセッションに入って送ります。報告者によると、Web の入力欄は「↩ で送信、⌘↩ で後回し」の二択になっており、通常の送信は作業の途中で届きます。スマホのブラウザで同じ二択が出るかは、私はまだ確かめておりません
- 長い作業は、こちらから区切りを頼んでおきます。保留はターンの終わりで解けるので、ターンを短くすれば訂正の届く機会が増えます
3 つ目は、依頼文の最後にこう添えるだけです。
作業は 3 段階に分けて進めてください。
各段階が終わったら、何を変えたかを 3 行で報告して、いったんターンを終えてください。
私から返事がなければ、次の段階へ進んでかまいません。ターンの終わりが「報告して止まる」場所になるので、スマホから送った訂正はその段階の終わりで確実に読まれます。手間は少し増えますが、取り返しのつかない方向へ進み続けるよりは、はるかに胃に優しいのです。
届かない訂正は、送っていないのと同じ。 だから私は、訂正が要りそうな作業ほど、ターンを短く切って任せるようにしています。
直らないときと、やらないと決めたこと
最後の手段は Stop です。ただし実行中のツール呼び出しはそこで打ち切られ、その途中の成果は失われます。ファイルの書き換えの途中で止めた場合は、止めたあとに差分を確かめてから続きを頼むのが安全です。
報告者は、同梱の Claude Code を 2.1.319 のバイナリに差し替えて元の挙動に戻していました。私はこれを真似しないと決めています。アプリの更新で上書きされますし、2.1.321 で直った他の修正まで手放すことになるからです。個人開発で自分のサイトやアプリの運用を任せている以上、「動くけれど、何の版かわからない」状態をつくるほうが、あとで高くつくと考えています。
次の一手は、Issue #108975 に自分の環境(Claude Code の版、iOS アプリの版)と、上のスクリプトで数えた結果を添えて反応を残すことです。同じ症状の報告が積み重なるほど、修正の優先度は上がりやすくなります。Remote Control そのものの始め方は、Claude Code を動かしたまま席を離れるなら、Remote Control を先に入れておく にまとめています。
まずは今日、作業中に iPhone から一言送ってみて、入力欄の文言を確かめるところから始めていただければと思います。