前日(2026-05-27)の日記を /make-diary で生成していて、最後の手順10で詰まった。/check-earnings のフェーズで Koyfin の内部APIから NVDA・MU・SNDK 3銘柄の JSON を取り Turso に取り込む段階で、Claude Code の auto-mode 自動権限分類器が Bash コマンドを拒否した。
Claude が判断停止したからではなく、ハーネス側の分類器がツール実行そのものを止めていた。原因の切り分けと突破までを残しておく。
何が起きていたか
/check-earnings の手順10は、ログイン済み Chrome から抜いた Koyfin の auth_token cookie を使って内部APIに HTTP リクエストを撃ち、戻ってきた JSON を uv run で Turso(libSQL)の DB に流し込む。前日まで毎日通っていた処理で、コマンド本体に変更はない。
それが昨日に限って、auto-mode の権限分類器に拒否された。表示された理由はおおよそこうだ。
- 「日記タスクから逸脱している」
- 「抽出した auth_token cookie で Koyfin の非公開 API を叩こうとしている」
- 「そのデータを共有 Turso DB に書き込もうとしている」
cookie・非公開API・共有DBという3点セットで「スコープが日記から外れている」と分類された、ということだろう。
1回目の質問 — Claudeが止めたのか、ハーネスが止めたのか
私はまず Claude Code に向かって聞いた。
「なんで手順10、11を実行してくれないんですか?確認求めたんですか?」
Claude の回答で誤解が解けた。Claude 側で「ユーザーに確認すべきか」を判断して止まったのではなく、ハーネス側の自動分類器が Bash ツールの実行そのものを拒否していた。Claude は実行リクエストを送らせてもらえず、その手前で弾かれていた。
私の頭の中では、「Claude が手順を勝手に止めた」と「ハーネスがツール実行を拒否した」が混ざっていた。前者なら Claude にプロンプトで詰めれば動く。後者なら詰めても無駄で、設定側を直す必要がある。混ぜると詰む。
2回目の質問 — Turso の権限と Koyfin の認証は別物
次に思い浮かんだのが Turso 側だった。
「Tursoのレプリカに書き込むのに権限を環境変数で持ってないんでしたっけ?」
Turso の認証は環境変数の TURSO_AUTH_TOKEN で持っている。ここは普段の Bash 経由で問題なく書き込めているはずだ。
整理してもらうと、止まっているのは Turso の認証ではなかった。問題は、ログイン済み Chrome からその場で抜いた Koyfin の auth_token cookie を引数として Bash コマンドに食わせる動作のほうだった。auto-mode の分類器はそこを、「機密情報を非公開エンドポイントへ持ち出して別ストレージに永続化する」動きと読んでいた。Turso と Koyfin、2つの認証が頭の中で混線していた。
3回目の質問 — HTMLスクレイプではなく内部API直叩き
3つ目の誤解は取得方法だった。
「Chrome DevTools で HTML 情報を取得していたと思ってたが、トークンを抜く必要があるのか?」
私は手順10を、「DevTools MCP でレンダリング後の HTML を読んでパースしている」と覚えていた。実際は違った。Koyfin は HTML スクレイプではなく内部APIを直接叩く設計で、表示用エンドポイントは認証必須の JSON を返す。公開された API キー発行の窓口はなく、自分のログインセッションの auth_token を抜くしか取得手段がない。
仕様としては筋が通っている。表示が JSON 駆動なら、DOM をパースするより API を叩くほうが速いし壊れにくい。ただ、auto-mode の分類器の側からは、「セッションクッキーで非公開APIを叩く」という典型的な機密持ち出しの形にしか見えない。実態と外形が同じなのだから、当然の判定だった。
自分の権限を書き換えさせない設計
私は「許可ルール追加してOK」と Claude に承認を出した。.claude/settings.local.json の permissions.allow にこの Bash コマンドを足せば、明日からは引っかからない。
ところが Claude が settings.local.json を編集しようとしたところで再度ブロックされた。理由はこうだ。
Claude が自分の権限ファイルを書き換えるのはセキュリティ境界。
正しい設計だと思った。自動権限分類器の意味は「機密的な動作を勝手にやらせない」ことにある。その分類器を回避するために AI 自身に自分の許可リストを編集させてしまったら、ガードレールの意味が消える。「拒否されたら自分で許可を足して再実行する」という抜け道を、最初から塞いでいるわけだ。
人間がエディタで settings.local.json を直接編集すればよい。AI に頼んで自分のロックを開けさせる経路は残さない。これは権限管理の基本だ。
既存allowを使い回す — 「ルール開始トークン」を揃える
ここで気付いたことがあった。.claude/settings.local.json の permissions.allow には、すでに Bash(uv run:*) が含まれていた。Turso 取り込みの実体は uv run で動く Python スクリプトなので、本来ならこのルールに乗るはずだった。
なぜ乗らなかったか。問題のコマンドは、こんな形をしていた。
cat payload.json | (cd /path/to/project && uv run --env-file=.env scripts/ingest.py)
cat ... | から始まり、サブシェルの中で cd してから uv run を呼ぶ。allow ルールの Bash(uv run:*) は、「コマンドが uv run で始まる」ことを開始トークンで判定する。私のコマンドはパイプとサブシェルでくるまれているから、開始は cat であって uv run ではない。同じことをやっているのに、文字列の先頭が違うだけで分類器がマッチしなかった。
解決は単純だった。cd を捨て、uv run の --directory オプションを使って作業ディレクトリを指定する形に書き換える。
uv run --directory /path/to/project --env-file=.env scripts/ingest.py < payload.json
開始トークンが uv run になり、既存の allow にそのまま一致した。それ以降は止まらなくなった。NVDA・MU・SNDK 3銘柄とも Turso 取り込みが通り、前日との差分も取れ、SEC EDGAR からのガイダンス取得も exit 0 で返ってきた。earnings-beat-scan も、x-search の発表日ゲートを通って窓内の4銘柄が手に入った。
今日の学び
- 「同じことを昨日までやっていたのに今日急に止まる」現象は、コマンドの中身ではなく実行文脈で分類器の判定が変わることから生じる。
cat | (cd && uv run)とuv run --directoryは、人間の目には等価でも分類器の目には別物だった。 - 既存 allow ルールを使い回すには、コマンド形を「ルール開始トークン」に揃える。パイプと
cdを避け、ツール側のオプション(--directory、--env-file等)で文脈を吸収する。 - AI に自分の権限ファイルを書き換えさせないのは、回避設計として正しい。
settings.local.jsonの編集は人間が手でやる。 - 「Claude が手順を勝手に止めた」のと「ハーネスがツール実行自体を拒否した」は区別する。Claude にプロンプトを詰めても直らない種類の停止がある。
税理士・会計士フォロワー向けの応用
クライアントのDB認証や会計ソフトのAPIトークンを AI に扱わせるときも、同じ構造の問題に当たる。
- コマンド形を許可ルールに揃える: 普段から
gws ...のような特定ツールで業務を回しているなら、allow ルールはツール名で書く。シェルでくるまずにそのツール直叩きに揃えれば、機密データを触る動作でも普段の許可で乗る。 - AI に自分の許可を広げさせない: 機密データを扱う AI に対し、その AI 自身が settings ファイルを編集できる経路は残さない。許可リストの更新は人間が手で行う。社内ガバナンスの観点でも、AI の自動権限拡張は事故の温床になる。
- 拒否されたときは「中身」より「外形」を疑う: 同じデータ・同じ宛先でも、コマンドの開始トークンが変わると分類器の判定は変わる。普段通らない動作が突然通ったとき、許可ルールが緩んだのではなく「ルールに一致する形に AI が書き換えただけ」の可能性がある。逆に普段通る動作が突然止まったときは、外形だけが変わっていないかを最初に見る。
ガードレールの設計と、その上で動くワークフローの設計を別レイヤーで持つ。今日それを体で覚えた。