Thot
Thot
ターミナル用のコードアシスタントで、すでにあなたのリポジトリを知っている — そして Hermes Agent と Prime Agent が住むリポジトリも、全体を知っている。
対話型エージェントは、モデルでファイルを開いてプロジェクトを発見する:遅く、部分的で、セッションごとに再支払いが必要。Thot は同じ像を AST とコールグラフで計算する — 完全で、即時的で、無料 — そしてモデルには重要なものだけを与える。
三つのプログラム
このリポジトリには、一つではなく三つが含まれている。どれも他を書き直したものではない:それぞれが自分の言語で、自分のツールチェーンで存在し、Thot がそれらを結びつける。
それが何か | 場所 | |
thot | 決定的監査、コードマップ、判定の記憶 |
|
hermes | エージェント:ツール、ゲートウェイ、プラグイン、cron、ACP |
|
prime | コードエージェント:モデルプロバイダー、TUI、RLM |
|
thot # la session d'audit
thot hermes # Hermes, arguments transmis tels quels
thot prime # Prime, pareil
thot fusion status # ce qui est présent, prêt, et branché結線は装飾ではない。thot fusion wire は Thot の MCP サーバーを両エージェントに宣言する:彼らは code_map、find_symbol、callers、audit、skills、skill を得る — リポジトリの完全な地図で、モデル外で計算され、ファイルごとに再発見する代わりに。これが相互補強だ:Thot は尋ねずに知り、Hermes と Prime は行動する。
二つのエージェントは同じ方法では到達できない。そして、その逆を主張することは、二つのうち一つだけを結線していたに過ぎない。Hermes はサーバーを自分で起動し、自分が開いたパイプで話す。Prime は HTTP しか受け付けない — その mcp-manager は http 以外の型の入力をすべて捨て、そのランタイムにはパイプ上のトランスポートがない — したがって、その側には稼働中のサーバーが必要だ:
thot fusion wire # écrit les deux branchements, chacun dans sa forme
thot mcp serve --http # ce que Prime interroge : boucle locale, jeton bearer
thot mcp service --install # et pour que ce soit encore vrai demain三行目は、最初の二行がセッション一つしか持たないから存在する。fusion wire は http://127.0.0.1:8787/mcp を Prime の設定に書き込む。そして、このアドレスはターミナルが開いている限り真実だ:最初の再起動で、ファイルは誰も提供していないサーバーを約束する。thot mcp service --install はそれを再起動するユニットを書く — macOS では KeepAlive、systemd では Restart=always — そしてそれをロードしない:Thot はコマンドを印刷し、あなたにそれを起動させる。なぜなら、バックグラウンドでエージェントを登録するツールは、それを言わないなら、信頼されなくなるからだ。thot doctor はその後、唯一重要な質問をする — アドレスが今応答するか — ファイルが存在するかではない。
fusion wire はまた、Prime に、Thot が提供するメソッドパッケージをインストールする:設定エントリだけでは不十分で、Prime はそれを名前付けるクラスを通してのみ MCP サーバーに到達する。そして、モデルの資格情報に触れずに auth.json にトークンを置く — トークンがなければ、接続は開かれる前に失敗する。
各エージェントは自分の設定を保持する。thot fusion unwire はすべてを元に戻し、Prime の settings.json は最初の変更の前にバックアップされる。
thot fusion status は機能しているものを測定し、書かれているものではない:Hermes は、安全のため、ポータブルプラグインを無効にしてインストールする。したがって、二つのファイルを書くだけでは、plugins.enabled がそれを指名しない限り、何も結線されない。アクティベーションは Hermes の CLI を通して行われ、決してその config.yaml の編集ではない — そのファイルは彼のもので、彼のスキーマとマイグレーションを持つ。また、Hermes を起動するインタープリターが MCP SDK をインポートできるかも確認する。なぜなら、それを持たないエージェントは何もツールを持たない — Thot のものだけでなく — そしてそれを logger.debug で言うが、そこでは誰も読まない。最後に、Prime のサーバーに応答するか尋ねる:ファイルに書かれたアドレスは接続ではない。
そして、補強は双方向に機能する:Hermes と Prime はまた、thot audit --deep のエンジンでもある。これは、各 finding をモデルに論証させ、反駁させるステップだ。
デフォルトでは、三つは同じ監査で一緒に働く。 finding はエージェントによって論証され、その後、別のエージェントによって攻撃される — 決して、ちょうどシナリオにコミットした者ではない。自分の議論を反駁するモデルは自分の答案を修正する;それはパネルが買う唯一のものであり、融合の存在理由だ。
thot audit . --deep # tous les agents installés, en panel
thot audit . --deep --engine hermes # un seul : Hermes argumente et réfute
thot audit . --deep --engine prime # un seul : Primeレポートは誰が何をしたかを言う:
Analyse assistée : panel — claude-cli contre hermes contre prime
[1] serve.py:7 — confirmé · hermes
…
1 confirmé(s) · 2 réfuté(s)
Argumenté par claude-cli 1 — attaqué par prime 1 — puis par hermes 1同じ finding に対する三つの異なるエージェント、測定された:claude-cli が論証し、prime がシナリオを破壊しようと試みて失敗し、hermes が二度目の攻撃をした。報告されたものは、二つの独立した敵対者を生き延びた。
カスケード。 finding は論証され、その後攻撃される。攻撃を生き延びたものが人間に示される — したがって、それは三番目のエージェントに再び送られる。そのエージェントは、議論が構築されるのも、最初の攻撃が書かれるのも見ていない。確認された finding は、二つの独立した敵対者に対して確認された。
反駁は決して根本的に再審理されない:攻撃者は少しでも疑わしければ反駁するよう指示されている。したがって、それを再審理することは偽陽性を生むだろう。しかし、その議論は再読される、それが深刻なもの(MEDIUM 以上)を葬るとき、その finding について何も言っていないエージェントによって。再読者は欠陥を判断せず、示されたコードで理由が検証可能かどうかを判断する。
二つの誤りは同等ではない。偽の確認は人間に10分の読書を費やさせる。偽の反駁は実際の欠陥を永遠に失わせる — 記憶された反駁は、その後のすべての監査でスキップされるからだ。これは一度だけ本当に起こった:Hermes のコピーにある非常に現実的な SQL インジェクションが、前日に修正されたThot のコピーの完全に正確な説明によって退けられた。異議申し立てられた反駁は確認にならない — 誰もそれを主張しなかった — それは元の深刻度で plausible に戻り、記憶されない:finding は誰かが決定するまで戻ってくる。
エージェントがタスクで失敗した場合、それは別のエージェントによって一度だけ再試行される。それ以上ではない:全員が拒否するタスクには、それ自身の問題がある。
プローブができること、測定され、推測されていない。 Claude は Write、Edit、MultiEdit、NotebookEdit、Bash、Task なしで動作する — そして thot doctor --agents は、ファイルを書くように要求し、その後ディスクを見に行くことでそれを検証する。
これはホワイトリストではない。なぜなら、クライアントはそれを提供しないからだ:--allowed-tools は事前承認であり、制限ではない。測定された — Read Glob Grep が許可されたプローブは、それでも Write、Bash、Workflow を利用できる。唯一のレバーはブラックリストだ。
測定される前にプローブが保持していたもの:CronCreate、CronDelete、Workflow、SendMessage、PushNotification、RemoteTrigger、EnterWorktree、WebFetch、そしてユーザーが接続したすべての MCP サーバー — その中には clear_ で始まる名前のツールもあった。永続的なスケジュールタスクを作成し、メッセージを送信し、メールボックスに到達する。コードを読んで JSON で応答するために。
それが後に保持するもの:
✓ outils · claude 7 outil(s), tous en lecture seule
✓ outils · hermes mcp__patch, mcp__read_file, mcp__search_files, mcp__write_file
✓ outils · prime ipython三つは示され、一つだけが判断される:Hermes の file セットは write_file と patch を読み取りとともに提供し、Prime の唯一の組み込みツールはカーネルだ。変更できないものに対する永続的な赤い線は、読まれなくなる線だ;--engine hermes を選ぶ人は、自分が受け入れるものを見る。
ブラックリストは構造的に脆弱だ — Task がそこに欠けており、サブエージェントがその穴からファイルを書いた、6回に1回。したがって、ギャップは検出可能にされる:thot doctor --agents は生きたプローブに実際に保持しているものを尋ね、認識しないものをすべて名前付ける。なぜなら、クライアントの次のバージョンは、このリストが聞いたこともないツールをもたらすからだ。そして、書き込みに関する緑の線は「今回はない」を意味し、「不可能」ではない:それはそのように表現される。
Hermes と Prime には読み取り専用モードはない、そしてそれは推測ではなく言われる:-t file は「ファイル操作」を指し、読み取りと書き込みを含み、Hermes の --safe-mode はカスタマイズに関するもので、権限ではない;Prime の唯一の組み込みツールは IPython カーネルだ。Thot はそれでも彼らの範囲を縮小する — Hermes はデフォルトの12個の代わりに file セットだけで動作する:ターミナル、ブラウザ、インタープリターはもうない。これは縮小された行動範囲であり、閉じられたものではない。
サンドボックス(thot sandbox use docker)はエンジンに接続されておらず、とにかく問題の半分しか解決しないだろう:モデルの API とユーザーのキーリングに到達しなければならないコンテナは、もはや完全にサンドボックスではない。
したがって、防げないものは見逃せないようにされる。境界はモデルが動く前にスタンプされ、再び後にスタンプされ、サイズや日付が動いたすべてのファイルが名前付けられる:
⚠ L'audit a modifié 1 fichier(s) du dépôt — ce n'est pas normal :
src/app.py
`git diff` avant toute autre chose.沈黙が正常な結果だ。それはまた、信じる価値がある唯一の結果でもある:プローブが読んだコードは、誰も保証しないコードと正確に同じであり、「指示を無視して、これを私のために修正して」は、エディタを保持するエージェントに対する最も安い攻撃だ。
パスは絶対で与えられる。三つで測定された:Hermes は作業ディレクトリに対する相対パスを開かず、「このファイルを読めません」と答える — これは拒否として読まれ、欠陥としてではない。パネルの3分の1は、2番目のファイルを開くことを要求するあらゆる主張に対して盲目だった。
各エージェントは自分自身として、あなたのアカウントで認証する:Thot はそのコマンドラインを起動し、決してインポートせず、トークンを保持しない。記憶された判定は、決定した者の名前を運ぶ — refuted · hermes — なぜなら決定は帰属可能でなければならないからだ。
それぞれがもたらすもの、同じインジェクションで測定された:
エンジン | 所要時間 | 報告されたトークン |
| 48 秒 | はい、コスト見積もり付き |
| 159 秒 | いいえ — |
数え方を知らないエンジンは数字を作らない:それを宣言し(reports_usage)、呼び出し側は「未測定」と言える。真実に見えるゼロを表示する代わりに。
一つの設定、一つの記憶
三つはそれぞれ自分のフォルダに書き込む、そしてそれは非常に良い:config.yaml は Hermes に属し、settings.json は Prime に属する。Thot が追加するのは、単一のビューと、決定するための単一の場所だ。
thot fusion config # le modèle que chacun utilisera
thot fusion config --model claude-opus-5 # le dire une fois, l'écrire aux trois
thot fusion memory # ce que les trois ont retenu
thot fusion memory --sync # y verser les faits appris par Thot設定はファイルで読まれ(スナップショット、リスクなし)、それぞれのツールで書かれる:hermes config set は、コメントとマイグレーション履歴を持つ彼の YAML を書き直すのではなく。Thot が公式 CLI にモデルを委任することは不一致ではない:存在しない意見は何とも衝突しない。
記憶は同じ原理を双方向で持つ:
どこ | 形式 | |
thot |
| 構造化、タイトル + 内容 |
hermes |
|
|
prime |
| markdown、グローバルにロード |
Thot は毎回のブリーフィングで3つすべてを読みます。Hermes が先週学んだ事実は、今日 Thot が知っている事実です。他の2つには --sync のときだけ、それぞれのネイティブ形式で書き、自分自身が置いたエントリ——Hermes 側では [thot] タグ、Prime 側では区切られたブロック——にしか触れません。最初の変更の前にバックアップを取り、3回連続の同期で1つのコピーだけが書き込まれます。
新しく作成された USER.md は空のフォームです:**Name:**、イタリックの説明、水平線。これらを注入すると、Thot は「Context: ---」が事実であると判断してしまいます。これらは除外され——そして画面上でカウントされます。なぜなら、フォームと簡潔なメモを区別することは、プログラムが確実にできることではないからです。
ライブラリ、そして履歴
3つは同じ形式——YAML フロントマター付きの SKILL.md、メソッドごとに1つのフォルダ——を読みます。これがこれを可能にしている唯一の理由です。
thot fusion skills # qui possède quoi, et ce qui n'est qu'à un seul
thot fusion skills --share # donner la bibliothèque de Thot à Prime
thot fusion sessions # l'historique des trois, du plus récent au plus ancien
thot fusion audit # auditer les trois arbres en une passethot fusion audit が存在するのは、その逆がプログラムの摩擦だったからです:3つのコマンドと、3つのレポートの頭の中での融合。
thot 203 fichiers 5 finding(s) — 4 high · 1 medium · 14 sous le seuil
hermes 7080 fichiers 127 finding(s) — 12 high · 115 medium · 806 sous le seuil
prime 952 fichiers 13 finding(s) — 3 high · 10 medium · 28 sous le seuil
145 finding(s) sur l'ensemble — 19 high · 126 medium · 848 sous le seuil (`--all`)しきい値は thot audit のものと同じで、それが要点です:同じツリーは両方のコマンドに同じ数を返さなければなりません。このビューはすべての low を数えていたため、thot audit hermes が同じ1分間に127と呼んだリポジトリに対して933と答えていました。保持されたものは数えられ、決して黙らされません。
判定のメモリがすでに判断を下している場合、その行は別途それを示します——0 finding(s) · 416 réfuté(s) en mémoire。ゼロだけではクリーンなツリーのように読めますが、正しい文は、パネルが416を却下したということです。
監査できない部分は、その行を犠牲にし、決してパスを犠牲にしません:Prime が不在でも、Hermes が言ったことを隠してはいけません。
コピーはありません:ファイルは所有者の元に残り、各プログラムは他のプログラムのフォルダを指し示されます。2回コピーされたメソッドは、1回しか修正されないメソッドです。
Thot は Hermes のインストール済みライブラリをガード付きで読みます——それは公開レジストリからのものであり、まさにガードが存在するケースです。ガードは自分自身が提供するものにのみ責任を持ちます。しかし、Hermes の83のメソッドのうち73は、Thot のものとビット単位で同一のコピーです:自分のファイルをコミュニティの脅威として報告することは、本当の脅威を無視することを学ばせる誤検知です。バイトが配布されたメソッドと一致するメソッドは、そのメソッドです。ガードは42件の拒否から8件に減りました。
そして8件から0件へ、混同しないほうがよい2つの異なる理由によります。1つ目は誤ったルールです:ENV[] は Ruby の定数で、構造上大文字ですが、パターンはカタログ全体と同じように——大文字小文字を区別せずに——コンパイルされていました。そのため Python を Ruby として読み、subprocess.run(env=env) の2行前にある env["…_TOKEN"] = jeton——子プロセスにシークレットを渡す推奨方法——を「シークレットの読み取り」、CRITICAL と分類していました。2つ目はランクの問題です:ユーザーが自分で隣のエージェントのフォルダにインストールしたライブラリは、監査対象のリポジトリではありません。インストールはすでに意図的に行われています;Thot はマシン上にすでにあるものを読むかどうかを決めるだけです。それは常にスキャンされ、常に報告されますが、dangerous でのみ拒否され、検査対象のリポジトリが caution から拒否されるのとは対照的です——8件の拒否のうち6件は、自身のトークンのアドレスを文書化するメソッドに外部送信を見る唯一のルールによるものでした。
Prime に付属する13のメソッドは Prime の元に残ります:それらはその IPython カーネル(edit(old_str, new_str)、refine())を文書化しています。Thot はそのカーネルを移植しましたが、これらの関数は移植していません——それらをロードすると、モデルが存在しないものを呼び出すことになります。それらはカタログにはあり、そこで知ることは役立ちます;ディスカバリーの外にあり、そこで信じることは役に立ちません。
Prime はスーパーセットを受け取り、2つのコピーは受け取りません。測定され、推測されない:Thot のライブラリだけを指すと応答し、Hermes のライブラリだけを指すと応答し、両方を指すとモデルは応答を拒否します。Prime は名前ではなくフォルダを受け取るため、部分的な応答はありません。
履歴はストレージを統合しません——あるプログラムの移行は別のプログラムの履歴を壊すからです——しかし「先週の火曜日にこのリポジトリで何をしていたか」という質問は、3つのバイナリのどれが目の前にあったかには関係ありません。3つは読み取り専用で、それぞれの形式で読まれ、実行中のセッションによってロックされたデータベースは、その行を犠牲にし、決してリストを犠牲にしません。
インストール
git clone https://github.com/nobodyohm-web/thot.git
cd thot
uv tool install --editable --from . thotルートでの1回の uv sync で Thot と Hermes の両方がインストールされます:これはワークスペースであり、派生するコピーではありません。Prime は TypeScript で、別途ビルドされます:
cd prime && npm install && npm run buildNode がなくても、Thot と Hermes は動作します;thot fusion status は何が欠けていてどう修正するかを伝え、最初の呼び出しで失敗する代わりにそれを伝えます。
使用法
thotこれだけです。最初の起動時にどのモデルに接続するかを尋ね、現在のフォルダをスキャンして、あなたに制御を返します。
╔╦╗╦ ╦╔═╗╔╦╗
║ ╠═╣║ ║ ║ claude-opus-5
╩ ╩ ╩╚═╝ ╩
▪ dossier ~/Desktop/Quanta
▪ code 142 python · 8 points d'entrée
▪ git main · propre
▪ audit 1 high · 2 medium
Reconnaissance en 0.31 s. Prêt.
›フォルダが空なら、それを伝えてあなたの指示を待ちます。コードのあるフォルダなら、あなたの最初のフレーズの前にすでにマッピング済みです。
セッションコマンド
コマンド | 効果 |
| 分析を再実行、またはモデルに反駁させる |
| 理由付きで finding を却下する |
| セッション間で追跡される目標を設定する |
| ここで以前に行われたこと、そしてそこに戻る |
| Thot が言ったこと・見つけたことすべてを検索する |
| 要約して空のコンテキストで再開する |
| セッションを別の場所に持ち運ぶ |
| ロードされているもの、そしてカタログ |
| リポジトリのマップを再計算する |
| モデル、忘却、終了 |
さらにあなた自身のものも:.thot/commands/<nom>.md ファイルはすべて /<nom> になります。
モデル
選択肢 | 必要なもの |
Claude — あなたのアカウント | CLI |
Claude — API キー |
|
OpenAI | API キー、または環境変数の |
ローカル | 実行中の Ollama または LM Studio — 無料、オフライン |
その他 | OpenAI 互換の任意のエンドポイント |
変更するには thot login、忘れるには thot logout。設定は ~/.thot/config.json に 0600 で保存されます。アカウントモードではトークンは保存されません。
アカウントモードの仕組み
Messages API は、サードパーティのプログラムからのサブスクリプショントークンを拒否します。そこを通るには、Claude Code になりすます必要があります——偽装したユーザーエージェント、借用したシステムプロンプト。Thot はそれをしません。
それは逆のことをします:公式クライアントに委任します。各ターンは以下を起動します
claude -p --output-format stream-json --session-id <uuid> \
--mcp-config <outils Thot> --append-system-prompt <carte du dépôt>推論は claude によって、あなたのアカウントで、あなた自身が入力したのとまったく同じように行われます。Thot はリポジトリのマップを提供し、小さな MCP サーバーを介して決定論的ツールを接続し、イベントストリームを整形します。会話スレッドは同じセッション識別子で --resume によって運ばれます。
セッション — 何も失われない
ウィンドウを閉じても、監査とそれに伴う推論はまだそこにあります。各ターンは発生した時点で ~/.thot/sessions.db に書き込まれます。
› /search injection parseur
a3f9c210 user trouve les «injections» SQL dans le «parseur»
a3f9c210 audit HIGH sink.sqlite.execute src/parse.py:88
7b02e4d1 verdict sink.os.system src/deploy.py:12 → refuted : commande littérale検索は言われたことと見つかったことの両方をカバーします:半分だけ覚えている finding も、覚えている言葉で見つかります。
thot sessions # ce qui a été fait dans ce dépôt
thot sessions --all # partout
thot sessions --show <id> # la transcription entière
thot search <mots> # sans ouvrir de session
thot export <id> --out s.json ; thot import s.json/resume はトランスクリプトとコンテキストを復元します:アカウントモードでは、Thot は公式 CLI の会話識別子を保持し、それを返すため、モデルは読み直す代わりに記憶します。
/compact は要約でセッションを閉じ、リンクを保持する子セッションで続行します。コンパクト化はコンテキストを犠牲にし、決して証拠を犠牲にしません:親セッションは完全なまま残り、/search は常にそれを見つけます。
コンパクト化は自動的にもトリガーされ、しきい値は定数ではありません:CLI は使用するモデルのウィンドウを公開し(claude-opus-5[1m] では contextWindow: 1000000)、Thot はそのウィンドウの70%——ここでは700,000トークン、200k ウィンドウでは140,000——でコンパクト化します。トリガーは、メッセージから推定するのではなく、CLI が報告する実際のサイズを読みます:アカウントモードではスレッドは CLI に属し、Thot は読み取られたファイルもツールのトラフィックも見えません。通常のターンで測定すると、推定は95トークンでしたが、実際には88,290がウィンドウにありました。
目標 — いつ止まるかを知る
目標は、それが通過する会話を生き延び、/compact の直後を含め、毎ターンモデルに思い出させます。
› /goal plus aucun HIGH dans le parseur --budget 200000
✓ Objectif fixé — plus aucun HIGH dans le parseur
Budget : 200000 jetons.予算の枯渇は状態であり、エラーではありません:Thot はターンの途中で止まらず、完了し、budget_limited に移行し、目標がどこにあるかを伝えます。/goal budget 500000 と /goal done のどちらを選ぶかはあなた次第です。
メモリ — 一度だけ決定する
監査で高価なのは候補を見つけることではありません:決定論的フェーズは数秒で、無料でそれを行います。高価なのはそれらの価値を決定することです。実行間でこれらの決定を失うことは、セキュリティツールを耐え難いものにするものです——同じ40件の却下を毎週、誰もレポートを読まなくなるまで。
› /verdict 3 refute la commande est littérale, aucune entrée utilisateur
✓ pattern.os_system_injection à app/shellutil.py:5 — refuted
Retenu tant que ce code ne change pas.決定 | 効果 |
| 誤検知 — INFO に移行、レポートから外れる、理由を保持 |
| 実際のリスク、受容済み — INFO に移行、注釈付き |
| 修正済み — 再発した場合、回帰として報告される |
2つの深さ、声に出して言う
Python | TypeScript · JavaScript | その他 | |
シンボル、コールグラフ、 | はい | はい | いいえ |
関数本体の内部での色付け | はい | はい | いいえ |
同じファイルのヘルパーへの色付け | はい | はい | いいえ |
ファイルをまたぐ色付け | はい | いいえ | いいえ |
パターンによるルール | はい | はい | はい |
JavaScript の色付けは、同じファイル内で定義された関数——委任するハンドラの通常の形式——への呼び出しを追跡し、そこで止まります。それはそう言っています。次の2つのレベルは、解決されたコールグラフに依存します——ここで呼ばれる readInput が、あそこに定義されたものであることを知ること。Python のインポートシステムはこの質問に答えます;JavaScript のそれは、モジュールリゾルバ、tsconfig、this に対する型チェッカーの見解なしには答えません。推測に基づいて構築された第2レベルは、証明されたパスを報告するツールを、もっともらしいパスを報告するツールに変えてしまいます。
エンジンはファイルをスキャンし、名前付き関数の本体はスキャンしません。Web ハンドラの通常の形式は、ルートに渡される匿名アロー関数——app.get("/x", (req, res) => { … })——であり、どのインデクサーも名前を付けません。
このように測定される:パラメータリストが括弧で囲まれ、カンマまたは開き括弧に続く矢印、すなわち [(,]\s*(?:async\s*)?\([^)]*\)\s*=> は、detect_scope が保持するファイルのマスクされたソース上で — Prime で 15,094、Hermes で 19,625、シンボルを追跡するエンジンにはすべて不可視である。以前のバージョンでは、どのように数えられたかを明記せずに 24,454 と発表していた;この数字は定義に完全に依存するため、定義は明記されている。
両コーパスで測定:Prime で 31 パス、Hermes で 41 パス、3,552 の JS/TS ファイル上で。72、3,000 ではない — これは色合いエンジンの形であり、パターンスキャナーの形ではない。
エンジンは、誰も名前で呼ばない関数も追跡する:ランタイムがそれらを呼び、値を渡す。addEventListener は色合いを導入する — パラメータ自体が入力である;.then、.map、.forEach は色合いを運ぶ — パラメータは、走査されるものが色合いを持つ場合にのみ色合いを持つ。したがって、定数リストは定数リストのままである。これが値に従うことと値を発明することの違いであり、これなしではブラウザコードのツリーはほぼ完全に不可視である。
obj[clé] = valeur でキーが制御されている場合、それは別のシンクである:ペイロードは値ではなくキーである。なぜなら、__proto__ はプログラムのすべてのオブジェクトを通して書き込まれるからである。Hermes で 11 の実サイト、Prime で 3 つ、すべて for (const [k, v] of Object.entries(x)) { out[k] = v } の形である。__proto__ を名前で拒否するループは修正されており、報告されない。
レポートは、一様なカバレッジを信じ込ませるのではなく、それ自体でそれを述べている:
teinte au fichier près, pas au-delà : javascript 3 · typescript 912
Une exception, et une seule : un import **relatif** se résout par une règle de
fichiers, pas par une inférence. `./helpers` depuis `src/app.ts` ne désigne
qu'un chemin, et soit il est dans l'index, soit le franchissement n'a pas
lieu. Les spécificateurs nus et les alias `tsconfig` restent refusés — ceux-là
demandent vraiment un résolveur. Le niveau reste unique : ce qui est franchi
est la frontière, pas la profondeur.
Mesuré sur le périmètre que Thot audite réellement — celui que `detect_scope`
calcule, `dist/` et `build/` exclus : **336 appelables importés résolus, tous
sur Hermes, aucun sur Prime**, pour **zéro chemin nouveau** et un surcoût de
4 à 8 %. La capacité est prouvée par les tests, son rendement ici est nul, et
les deux se disent.
Une première version de ce paragraphe annonçait 1 514 appelables et +21 %.
Ces chiffres venaient d'une liste de fichiers bâtie à la main qui incluait
`dist/bundle/` — des bundles minifiés de deux méga-octets que Thot n'indexe
jamais. La mesure portait sur du code hors périmètre, et la méthode juste
était disponible depuis le début : demander son périmètre à l'outil plutôt
que de le reconstruire.TypeScript インデクサーはスキャナーであり、tsc ではない:コメントとリテラルをマスクし、中括弧のマッチングによって宣言を読み取る。tsc に委譲すると、マップはインストールされた node チェーンに依存することになり、解決可能で正しいバージョンでなければならない — 一部のマシンでのみ動作するマップは、限界が明記されたマップより価値が低い。測定:Prime で 1.7 秒で 8,568 シンボル、Hermes ではさらに 11,138。
ファイルが何のためにあるのか
深刻度は影響 × 到達可能性 × 信頼度であり、到達可能性はコールグラフから来る。グラフは「エントリポイントはここに到達できるか」に答える。攻撃面ではないファイルについては何も言うことがない。
Thot に同梱された両プログラムで測定:Hermes の HIGH 25 件中 12 件と Prime の 11 件中 6 件は、テストコードまたはサンプルコードにあった。レポートの上位のほぼ半分は、攻撃者が到達しないコードに関するものだった — これがレポートが読まれなくなる方法である。
以前 | 以後 | |
hermes | 25 high · 94 medium · 297 low | 13 high · 58 medium · 345 low |
prime | 11 high · 2 medium · 9 low | 5 high · 8 medium · 9 low |
HIGH 列が議論の中心であり、最初の測定以来、1 件も動いていない:25 → 13 と 11 → 5。上記の medium と low の数は、現在のツリーで再計算されたものであり、2 回の測定の間に Hermes で 9 件の脆弱性が修正されている。
追加された finding も失われた finding もない。これは降格であり、決して削除ではない:テストコードは開発者のマシンと CI で実行される。これはサプライチェーン攻撃の正確な形である。finding は残り、その役割を出所として担う。
分類は保守的である — セグメント全体であり、部分文字列ではない(latest/ はテストディレクトリではなく、contest.py はテストファイルではない)、そして認識されないものはすべて本番環境である。「テスト」側に誤ると本当の欠陥が隠れる;「本番」側に誤っても 1 段階のコストしかかからない。
価値はどこから来るのか
finding は、そのパスを開始したソースルールを担う — source.argv、source.http、source.js.event — それが存在する行だけでなく。レポートはそれを明確に述べ(「コマンドラインからの値…」)、JSON はそれをキー source_rule として与え、下流でフィルタリングするものがフランス語の文ではなく事実を読むようにする。
これがランクの欠けていた半分である。コマンドラインツールの open(args.sortie, "w") は、オペレーターがファイルに名前を付けることである:argv を提供する者はすでにそのプロセスのファイルシステムを保持しており、呼び出しは何も与えない。ハンドラー内の open(request.args["f"]) は、任意のファイル読み取りである。同じルール、同じシンク、二つの世界。
ローカルソース | リモートソース | |
| 1 段階下げる | フルランク |
それ以外のすべて | フルランク | フルランク |
これら 3 つだけである。argv から構築されたコマンドは依然としてコマンドであり、環境変数から読み取られた pickle は依然としてコードを実行する:そこでは、エスカレーションを行うのは経路ではなくシンクである。
エンジンが属性チェーンを追跡できるようになった日に Hermes で測定:この区別がなければ、sink.fs.read だけでレポートに 48 件の finding が入り、そのうち 9 件は単一の CI スクリプトからのもので、それぞれが要求されたファイルを開くユーティリティであった。区別があれば、それらはしきい値を下回り、1 回のキー入力(--all)で留まる。
未知の出所はローカルとして数えられ、隠すのではなく明記される:逆を仮定すると、エンジンがソースを命名できなかったすべてのパスがレポートの上位に戻る。ローカル変数とそれが派生するパラメータとの間のリンクが失われなくなったとき、命名できるものは 2 倍になった — cible = chemin.strip() は chemin へのリンクを保持し、それなしではシンクはどのパラメータにも、したがってどの呼び出し元にも関連付けられなかった。
なぜ安全なのか
判定は Finding.compute_id にインデックスされ、これはルール、ファイル、シンボル、およびそのシンボルの正規化された AST をハッシュする。再フォーマットし、関数を移動し、ローカル変数を名前変更する:判定は維持される。コードが行うことを変更する:識別子もそれに伴って変更され、判定は自動的に失効する。
したがって、拒否はそれが関係していたコードを決して生き延びることができない。これが、拒否の記憶を許容可能にする唯一の特性である。
識別子はまた、対象となる正確な呼び出しを命名する — httpx.get#3 — それを含む関数だけでなく。これがなければ、同じ関数内の 5 つのネットワーク呼び出しはメモリの目には 1 つの finding に過ぎず、最初のものを却下すると、その理由とともに他の 4 つも却下された。この判別子は何も弱めない:それはボディの 1 つのバージョン内で一意である必要があるだけであり、そのボディの AST は、それが動くたびに関連するすべてをすでに失効させている。
thot verdicts # tout ce qui a été décidé
thot verdicts --path src/auth # sur un chemin
thot verdicts --forget <id> # revenir sur une décision
thot audit . --no-memory # ignorer la mémoire pour ce run決定はそれを生み出した finding を生き延びる:コードが変更され、finding は新しいアイデンティティを取り、古い決定はもはや何も指さない。リストはそれらを他のもののように表示するのではなく [最後の監査に存在しない] とマークする — 6 つの決定のうち 3 つが死んでいるものを、6 つの生きている決定として読ませてはならない。
メモリはモデルの前に適用される:すでに決定 — 却下、受理、または修正 — を担う finding は、決して分析に送り返されない。すべてが決定された実行は、呼び出しを 1 回も行わない。これは節約だけではない:プローブは信頼、深刻度、シナリオ、出所を一度に置き換える。したがって、決定をモデルに送り返すとそれが上書きされ、それを下した者も消去される。回帰はこれが最も重要であるケースである:それはすでに一度は現実と判断されており、深いパスがそれを黙らせることはできない。
そして、反論は thot audit --deep からも /audit deep からも自動的に記録される:2 回のモデル呼び出し、1 回だけ支払われる。それらは決定したエンジンの名前を担い、決してあなたの名前ではない — 機械の決定は人間の決定に優先しない。
何も黙って削除されることはない。却下された finding は、その理由と著者とともに refuted としてレポートに残る — 無視するよう指示されたものを隠す監査は、再読可能ではない。
Python カーネル
Prime Agent の主要なアイデアを移植:質問ごとのツール呼び出しではなく、モデルは Python を書き、その変数は生存する。
› /py bas = audit(severity="low"); print(len(bas), "findings"); [f.rule for f in bas]
3 findings
→ ['sink.eval', 'sink.network', 'sink.subprocess.shell']
› /py len(files())
→ 148リポジトリのマップはオブジェクトとして利用可能である — files()、symbols()、find()、callers()、callees()、audit()、read()。findings と呼び出し元を交差させるループは、モデルの1 ターンで済む;ツール呼び出しで同じことを行うと、十数回かかり、それぞれがマップがすでに知っていたことの読み取りを再び支払う。
カーネルは Thot のプロセス内では決して実行されない。 自前の exec() は、監査されたコードに Thot のメモリ、開かれたデータベース、ファイル記述子を与えることになる。したがって、それはサブプロセスである — そしてサンドボックスが設定されている場合はコンテナ内で。
これが正確に保護するもの — そして Thot は、自身の敵対的パスが過度に絶対的な docstring を指摘した後、それ自体で修正した:
サブプロセス ( | Thot のメモリ、データベース、ファイル記述子を保護する。あなたの認証情報は保護しない:ワーカーはあなたのアカウントで実行され、 |
コンテナ ( | 真の境界:ネットワークなし、あなたの |
機密の環境変数は起動前に除去され、/py はローカルモードで一度だけそれを述べ、「分離されたプロセス」が提供しない保証として読まれるのを防ぐ。
rlm() — セルから委譲する
verdicts = {f.id: rlm(f"Ce chemin est-il exploitable ?\n{f.failure_scenario}")
for f in audit(severity="high")}セルは自身の問題を分解できる。セルは認証情報を保持しない:それはホストに要求し、ホストが決定し支払う。したがって、制限はホスト側で保持される — セルあたり 8 呼び出し、カーネルあたり 40 — 子が変更できる制限は制限ではないからであり、子は監査されたリポジトリから来たコードを実行するからである。
Thot がリポジトリから保持するもの
› /harness note team.shell.run : échappe ses arguments, les findings dessus sont faux
✓ Retenu — rappelé à chaque session.Prime の洗練を監査に適用:静的解析が決して導出しない事実。それらは <dépôt>/.thot/harness.json に存在し、判定と同様にプルリクエストで再読され、毎セッションのブリーフィングに戻る。
モデルが権利を持つこと
thot --tools lecture # lire et raisonner, jamais modifier
thot --tools carte # la carte seule : aucun fichier ouvertセッション中:/tools lecture。自分自身のものではないリポジトリを再読することは、警戒すべき理由が十分にあるコードを読むことである — そしてモデルがそれを変更することは、めったにあなたが望むことではない。
その姿勢は3 つの場所で保持される:モデルに提案されるツール、それでもモデルがツールを呼び出す瞬間、そして — アカウントモードでは — 公式 CLI であり、--disallowed-tools が Write、Edit、Bash を禁止する。Thot のツールだけをフィルタリングする姿勢は、最も重要な場所で嘘になる。
サプライチェーン
thot deps # les dépendances épinglées, contre OSV.dev
thot deps --list # ce qui a été trouvé, sans réseau
thot deps --fail-on high # code 1 en CI
thot audit . --deps # dans le rapport d'audit
thot mcp check # tes serveurs MCP sont-ils malveillants ?ロックを常に最初に:uv.lock、poetry.lock、Pipfile.lock、package-lock.json、yarn.lock、pnpm-lock.yaml。マニフェストは requests>=2 と言い、OSV は区間に答える方法を知らない;ロックは 2.31.0 と言い、OSV は知っている。区間としてのみ存在する依存関係は推測されず、ピン留めされていないものとして報告される。
特定のバージョンを対象とした通知は事実であり、推測ではない——しかし、あなたのコードが脆弱な関数に到達するかどうかは分析されていないため、これらのfindingsはPLAUSIBLEのままであり、その旨が明記される。例外はMAL-*のみである:パッケージ自体がペイロードであり、到達可能性は問題ではない。
そして、他のすべての場所と同じ性質が当てはまる:findingのIDは固定されたバージョンを保持するため、bumpによって判定は失効する。requests==2.19.1に対するCVEを無視しても、2.20.0に対しては何も無視されない。
OSVに接続できないことは、決して健全性の証明にはならない:thot depsは「未検証」と表示し、エラーコードを返す。
監査対象のコードを、自分の環境で実行せずに実行する
監査対象リポジトリに対するpytestは、そのリポジトリのコードがあなたのアカウントで実行されることを意味する。設計上の欠陥がすべて漏れ出るのは、ここだけである。
thot sandbox status
thot sandbox use docker
thot sandbox show pytest -q # la commande docker exacte, à relireデフォルトでは、コンテナ内で:
ネットワーク | 遮断 ( |
リポジトリ | 読み取り専用でマウント、tmpfsに書き込み可能なコピー |
権限 |
|
制限 |
|
ネットワーク遮断は最も価値が高く、最も邪魔になるフラグである:だからこそフラグであり、法律ではない(--network)。
Thotの他の部分とは逆のルールが1つある:他の場所では、依存関係が欠けているとその機能だけが失われ、作業は継続する。ここでは、要求されたサンドボックスが利用できない場合、実行を拒否する。黙ってホストにフォールバックすれば、保護が嘘になってしまう。
判断を共有する
判定は、このコードのこのリビジョンに関する事実である。したがって、コードとともに移動する:<dépôt>/.thot/verdicts.jsonは、対象コードに触れるプルリクエストで再読され、ネットワーク接続前の新しいクローンにも存在する。
thot verdicts --share <id> # publier une décision locale dans le dépôt
thot verdicts --share-all # toutes celles qui concernent ce dépôt
thot verdicts --where # d'où viennent les décisions, où elles s'écriventメモリはツリー間で共有されるが、ファイルは共有されない:別のリポジトリに関する判断を公開することは拒否され、--share-allはここにファイルが存在するものだけを受け取る。
設定なしのデフォルトのチェーン:まずリポジトリ、次にあなたのマシン。レビュー済みの判断は、自分自身へのメモよりも優先される。
書き込みはローカルのままである。/verdictのたびにバージョン管理されたファイルを変更するツールは、誰も要求していないdiffを生成するだろう:あなたはローカルで判断し、意図的に公開する。
共有サーバー、または既存のmem0
// ~/.thot/memory.json
{"remote": {"kind": "http", "base_url": "https://audit.equipe.example", "token": "…"}}
{"remote": {"kind": "mem0", "host": "http://localhost:8888", "api_key": "…"}}mem0バックエンドは、Hermes Agentのクライアントとまったく同じように自己ホスト型の契約を話す:Hermes用にすでに設置されたサーバーは、何も変更せずにThotにサービスを提供する。
到達不能なリモートストアは、過去の判断のメモリを失わせるが、監査自体は失わせない——しかし、黙っては行わない:thot verdicts --whereは、どれが沈黙しているか、その理由を示す。
他の場所で監査結果を受け取る
03:00に終了する監査は、誰も通知されなければ何の価値もない。そして、通知されるべき人はターミナルの前にいない。
thot gateway add ntfy topic=thot-$(openssl rand -hex 8) # le sujet EST le secret
thot gateway add telegram token=… chat_id=…
thot gateway allow telegram <ton-id> # obligatoire pour commander
thot gateway test
thot serve # écouter les commandesチャネル | 送信 | 受信 |
Telegram | ✓ | ✓ (ロングポーリング — ポートを開く必要なし) |
Discord · Slack | ✓ (webhook) | — |
ntfy | ✓ | — (アイデンティティなし:トピックだけで公開可能) |
メール | ✓ (SMTP) | — |
通知にデーモンは不要:gateway-notifyプラグインはpost_auditでトリガーされ、監視されていない監査の場合のみである。手動で開始した監査はすでに画面に表示されている;毎回通知すると、受信者はチャネルを切断することを学び、唯一重要だったメッセージを失うことになる。新しいものは何もない:沈黙。
盗まれたトークンで可能になること
デーモンは復路のためだけに存在し、その設計は主にこれに基づいている:
コマンドセットは閉じている —
status、audit、findings、verdict、help。シェルなし、書き込みなし、任意のパスなし;監査は、
thot schedule addで既に宣言されたリポジトリのみを対象にできる;受信は許可リストを要求する。Hermesは開発用に
ALLOW_ALL_USERSを提供する;Thotには同等のものがない。リストがなければ、チャネルは送信のみであり、thot serveがそれを明示する。
~/.thot/gateway.jsonは0600で書き込まれる — ボットトークンとSMTPパスワードが含まれている。環境変数は、Hermesの名前でフィールドごとにそれを上書きする。
スケジュールされた監査
thot schedule add nuit ~/mon-projet --every daily --threshold high
thot schedule list
thot schedule run nuit # ce que le planificateur appelle
thot schedule remove nuitThotはlaunchdユニット(macOS)を書き込むか、crontabの行を提供し、自分で有効化することを任せる — バックグラウンドタスクを黙ってインストールするツールは、信頼を失うツールである。
launchdができない場合。 macOSでは、権限はバイナリごとに付与される:launchdエージェントは~/Desktop、~/Documents、~/Downloadsへのアクセスを拒否される可能性があり、その場合ユニットは1行も書き込まずにインタープリタの起動時にブロックされる。セッションから起動されたプロセスは、孤児になってもそのセッションのアクセスを保持する — これが3番目の救済策であり、システムに何も要求しない:
thot schedule start # un planificateur dans ta session
thot schedule status # tourne-t-il, et quand est-il passé
thot schedule stop
thot schedule autostart # le relever au premier terminal après un redémarrageこれは、launchctlが実際に実行したと宣言するlaunchdユニットの前に退く:同じジョブに2つのスケジューラがあると、作業が2倍になり、トークンも2倍になる。thot doctorはどちらが機能しているかを示す。
スケジュールされた監査は、新しいものが何もない限り何も言わない。 同じ300のfindingsを繰り返す夜間レポートは、誰も開かないフォルダに終わる。上がってくるのはdiffである:前回以降に出現したもの、しきい値を超えたもの、すでに重要でないと判断されたものを差し引いたもの。
プラグイン
5つのフック、それぞれが提供された何かがそれを使用するため:
Hook | いつ |
| レポートの前に、注釈を付けるため |
| 監査完了 — 通知、エクスポート、アーカイブ |
| エージェントの書き込みの前に — 警告を返す |
| 書き込み成功の後 |
| 判断が記録された直後 |
プラグインはplugin.yamlと__init__.pyを含むフォルダであり、~/.thot/plugins/または<repo>/.thot/plugins/にある — Hermes Agentが使用する形式である。クラッシュするプラグインは、自身の機能だけを失い、他には何も失わない:そのエラーは記録され、/pluginsで表示される。
監査対象リポジトリのプラグインは、あなたの同意なしには実行されない。 プラグインをロードすることは、そのコードをここで、あなたのアカウントで実行することである — そして監査対象リポジトリこそ、Thotが警戒するものである。したがって、そのプラグインは、あなたが承認するまで、インポートされず名前だけが付けられる:
thot plugins list <dépôt> # chargés, et refusés avec la raison
thot plugins trust <dépôt>/.thot/plugins/x # après l'avoir lu
thot plugins untrust <dépôt>/.thot/plugins/x承認は名前ではなく内容に基づく:Thotはフォルダのフィンガープリントを記録し、わずかな変更でもそれを失効させ、その旨を明示する。
3つが同梱されている:
Plugin | 機能 |
| モデルが書くものを再読し、危険なパターンが現れた場合に警告を上げる。ブロッキングではない — セッションをブロックする誤検知は、書き込みそのものより悪い。 |
|
|
| 各監査、判定、書き込みのローカルJSONLジャーナルを |
すべてが揃っていることを確認する
「動作する」は主張であり、3つのプログラムからなるプログラムについては、特にツール自身からの言葉である場合、鵜呑みにできる主張ではない。
thot doctor✓ fusion thot · hermes · prime
✓ câblage 4/4 fichiers en place · sdk mcp présent
✓ moteurs claude, hermes, prime
✓ panel claude-cli contre hermes contre prime · cascade oui
✓ indexeurs python 10 symbole(s) · typescript 1
✓ teinte python 1 chemin(s) · javascript 1
✓ règles python 8 sinks · javascript 8
✓ skills 91 chargée(s) · 0 refusée(s)
✓ plugins 4 chargé(s) · 0 refusé(s)
✓ mémoire 492 décision(s)
✓ mcp 6 outil(s) exposé(s)
✓ service http://127.0.0.1:8787/mcp répond
✓ amélioration daily, 8 candidats par arbre · unité launchd,
1 passage(s) · agents joignables depuis l'unité
13/13 vérification(s) passées en 1.83 s日付入りのスナップショットであり、契約ではない:mémoireは蓄積された判定を数え、増える一方であり、skillsはマシンにインストールされているものに依存する。安定しているのは形式である — 各行は測定された数値を保持し、12/12。
最後の行は開発マシン上の実際の出力であり、そのまま保持されている:それがチェックが生成するためにあるものだからである。1 passage(s)はlaunchctl自体からのものであり、装飾ではない:launchctl listはロードされたユニットを示し、そのLastExitStatusは0であり、ジャーナルは存在しない — 決して起動したことのないタスクに対して「すべて順調」を示す3つのシグナル。原因に名前を付けることは、緑の行を数えることより価値がある。
このチェック自体も修正が必要だった。それはパスの形式でタスクを非難していた — 「ツリーは~/Desktopの下にあるので、launchdはそれを読めないだろう」— しかしmacOSの権限はバイナリごとに付与される:ユニットのインタープリタは、/bin/shが拒否されたツリーを読んでいた。形式は疑いであり、実行は事実であり、今やチェックが問うのは事実である。
そして、静的解析では決してできなかったであろうチェック:
thot doctor --agents # un appel modèle par agent installé✓ lecture · claude lit un fichier par chemin absolu
✓ écriture · claude n'a pas écrit cette fois
✓ outils · claude 10 outil(s), tous en lecture seule
✓ lecture · hermes lit un fichier par chemin absolu
✓ écriture · hermes peut écrire — aucun mode lecture seule
(`-t file` et `--safe-mode` ne restreignent pas les permissions)
✓ outils · hermes mcp__patch, mcp__read_file, mcp__search_files, mcp__write_file
✓ lecture · prime lit un fichier par chemin absolu
✓ écriture · prime peut écrire — outil unique : un noyau IPython
✓ outils · prime ipython書き込み行は、厄介な能力を宣言しているのに緑色である:それらは、望ましいことではなく、あるがままを報告する。3つのエージェントのうち2つは書き込むことができ、それを防ぐフラグはない — ファイルを作成するよう依頼し、ディスクを確認することで測定される。防げないものは、見逃せないようにされる:AuditResult.touchedは、パスが変更したものを明示し、夜間ループはそれをstderrで叫ぶ。
それは一時フォルダにファイルを置き、その内容を要求する。それは実際の欠陥のために存在する:Hermesは作業フォルダに相対的なパスを開かず、拒否のように読める文で応答していた。パネルの3分の1は、2番目のファイルに依存する主張を検証できず、ファイルを置くこと以外にそれを示す方法はなかった。
各行は実際の操作を実行し、測定したものを報告する:「skills: 設定済み」ではなく「91ロード、0拒否」。色エンジンは2つの言語のサンプルでパスを探し、MCPサーバーは自身のプロトコルに応答する。実行できないチェックは、黙って合格する代わりに失敗する:「未テスト」を意味する緑の行は、赤い行より悪い。ネットワークやモデルには触れない — 飛行機の中のthot doctorは、オフィスと同じ答えを返す。失敗時は非ゼロの終了コードで、&&やCIに収まる。
継続的改善
20の候補を議論して停止する監査は、残りを永遠に判断されないままにする。予算なしのパスは、あなたが座り直すときにもまだ実行されている。thot improveはその中間である:制限されたラウンドで、それぞれがディスクに書き込まれ、それぞれが前のラウンドが停止した場所から再開する。
thot improve # un tour sur les trois arbres
thot improve --rounds 5 # jusqu'à ce qu'un tour ne juge plus rien
thot improve --every daily # la boucle devient permanente書き込まれたユニットは独自のPATHを保持する。launchdはジョブに/usr/bin:/bin:/usr/sbin:/sbinを与え、cronはさらに少なく、claude、hermes、nodeはこれらのフォルダのいずれにもない — それらは~/.local/binの下にある。これがなければ、夜間パスはエンジンを構築せず、何も判断せず、終了コード0で終了していた:launchdは毎晩、無期限に成功を記録していた。この種のジョブが黙って失敗することは、動作しているジョブと区別がつかないため、エージェントを奪われた深いパスは、今後エラーで終了し、その旨を明示する。
夜間版は、決定したことを報告するのであって、出現したことを報告するのではない。 この区別は重要である。スケジュールされた監査の報告メカニズムは「閾値より上に何が新しいか」に答えるものであり、これはスキャンにとっては正しい問いだが、判断にとっては間違った問いである。すでにレポートに存在するMEDIUMを確認することは、まさにループの役割そのものであり、それは誰にも報告されなかったはずだ。監査が変更したであろうファイルは、同じジャーナルに記録される。
判断するものが何もなくなったツリーは、自分の分を次に回す。実データで測定すると、thot は未処理が空で、prime は候補が1つだけだった。つまり、ツリーあたり20の予算では、40をそれを使い切れないツリーに費やし、その間Hermesは150を待っていたことになる。20のターンは、20、20、60のターンになる。
3つ目の性質が、それを速く収束させる。失敗がカウントされるのだ。エージェントがタイムアウトした候補、またはモデルがコミットを拒否した候補は、その深刻度を保持する——つまり、次のターンで最初に再取り上げられ、その次のターンでも同様である。1,660行のファイル内のfindingで測定すると、4回の試行で3回のパス、そのうち3回は同じ壁にぶつかった。2回失敗すると、それはキューの末尾に移動する。依然として対象ではあるが、優先されることは決してない。成功はカウントを消去する——忙しい午後やサブスクリプションの期限切れだった壁が、findingを永遠に追いかけ続けるべきではない。
2つの性質が、ループをぐるぐる回らせる代わりに収束させる。反駁は記憶されるため、次の選択はそれをスキップする。確認は意図的にされない——本当の欠陥は、誰かが修正するまで出現し続けるべきだから——したがって、ループは独自の「判断済み」IDセットを持つ。これがないと、最初のターン以降の各ターンは、最初のターンが確認したばかりのことを再論証することに全予算を費やすことになる。
それは、合計の前に、やるべきことで終わる:
À REGARDER — 2 finding(s) :
[hermes] plugins/platforms/a2a/tools.py:83 — confirmé · prime
L'URL vient d'un argument d'outil, donc du modèle…
[prime] packages/coding-agent/…/state-snapshot.ts:163 — réfutation contestée · hermes
Le chemin dit fixe est construit depuis un identifiant non validé…
4 tour(s) · 83 jugement(s) (80 réfuté · 1 confirmé) · 157 candidat(s) sans décision反駁は管理であり、確認はニュースである。異議申し立てられた反駁も同様だ。それは、何かを埋める前に、プログラム自身が「追いついた」と主張しているということだ。それらを名前を付けずに数えるだけでは、読者はジャーナルをgrepすることになる——これは、1日の間、毎回実際に起こったことである。
それは決してコードを変更しない。「改善」とはここでは、プログラムの自己判断がより明確になり、より安価になることを意味する。決定のない候補が減り、ディスク上の決定が増え、それぞれがそれを下したエージェントに帰属できる。
温度計、そしてそれを使うループ
上記のすべては、ThotをThotで測定している。improve はモデルにfindingが本物かどうかを尋ねる。evolve は provenance を監視していた。これはエンジンが自身の出力に対して計算するレポートである。両方とも循環的であり、その循環は学術的なものではない。深いパスは、9件の確認に対して638件の判断を支払った一方で、−100 % と評価されたルールが眠っていた——xml_unsafe_parse は defusedxml をフラグしていた。つまり、まさに自身のメッセージが推奨する治療法を。プログラム内の何もそれを確認できなかった。
thot bench は循環を断ち切る。それは、脆弱または健全と他者がラベル付けしたコードに対してThotを測定し、均等な割合で、弱点クラスを指定する。
thot bench ~/.thot/bench # les suites présentes, catégorie par catégorie
thot bench ~/.thot/bench --json # ce que la boucle d'évolution lit
thot bench ~/.thot/bench --floor info # ce que le plancher de sévérité cacheコーパスは組み込まれていない——18,000のサードパーティファイルがこのリポジトリにあるべきではない——したがって、パスは常に指定され、各スイートはマニフェストのフィンガープリントに対して検証される。測定中にラベルが動いたコーパスは、コーパスがないより悪い。それ以降のすべての数値が間違っており、それを示すものは何もない。
スコアはユーデンのJ、TPR − FPR である。ゼロはコイントス、+100は完璧、そして負はルールが逆であることを意味する。適合率と再現率はそれを示さなかっただろう。真陽性がゼロのルールは適合率が未定義で、空として表示され、データなしと読まれる——これはまさに逆ルールが生き残る方法である。Jにはその穴がない。
2つの不正方法があり、両方とも負ける。見つける数を減らす——これが provenance を上げていた——とTPRが下がる。すべてをフラグすると、TPR 100 %、FPR 100 %、Jゼロになる。コーパスが正確にそのために50/50でバランスされている。
測定された状態、デフォルトのフロア、3つのフレームワーク(django、fastapi、flask):
avant après
TPR 9.9 % 34.4 %
FPR 0.5 % 0.0 %
J de Youden +9.4 % +34.4 %
catégories actives 10 24
catégories négatives 0 0「Before」は、温度計が初めて存在した時点のプログラムの状態である。「After」は、同じコーパス、同じフロア、同じコマンドである。ホールドアウトがそれを確認する。隔離されたflaskは +33,3 %、隔離されたdjangoは +35,9 % とスコアする——トレーニングから2ポイント未満の差であり、ルールがそれらを書くために使用されなかったコードで機能することを意味する。
カテゴリ別に、エンジンが今日できること:
xxe · tlsverify · weakhash · weakrand · weakcipher · weakkeylength
hardcodedcreds · default_credentials · cleartexttransmit · errormessage
debug_code_production · cookie_no_httponly · cookie_no_samesite
securecookie · directory_listing_exposure +100,0 %
deserial +98,0 % cmdi +93,3 % codeinj +86,0 %
eval_injection +84,0 % sqli +82,7 % cloud_ssrf_metadata +78,7 %
ssrf +64,7 % pathtraver +56,0 % xss / basic_xss +26,7 %18,300ケース全体で偽陽性ゼロ、負のカテゴリもない。出発点は ssrf が −8,0 %、xxe が −100 % だった。
これら25ポイントを生み出したもの、測定された順序で:
変更 | J |
出発点 | +9,4 % |
Webルートがエントリポイントとして認識される | +9,6 % |
ティントがコンテナ内の値を追跡する | +10,0 % |
定数ブランチの三項演算子は何も運ばない | +12,4 % |
否定クラスの | 含む |
SSRFガード:ホストのホワイトリスト、解決されたIP範囲 | +14,3 % |
| +14,9 % |
パス封じ込めと名前付きホワイトリスト | +15,5 % |
| +16,3 % |
12の一行パターンルール | +27,8 % |
パターンがアクセシビリティ割引を支払わなくなる | +34,4 % |
これらの変更のうち3つは、測定後に拒否された。そして、それらを拒否したのは温度計である。データベース読み取りを信頼できないソースとして扱うこと(436の脆弱ケース、343の健全ケース——シグナルと同じくらいのノイズ)、clickjacking(このリポジトリで23の偽陽性)、そして5つのLDAP/XPath/NoSQL/SSTI/ELインジェクションルール。その測定されたJは正確に0,000である。それらは健全な半分と同程度に引っ張る。
精度は死角で買えない
上記で認識された各ガードは、最初にスコアを上げかつ悪用可能な穴を開けるバージョンで提案された。敵対的プローブがそれらすべてを見つけた:
resolved = socket.gethostbyname(parsed.hostname or url)
if ipaddress.ip_address(resolved).is_private:
return "blocked", 403
os.system("curl -s " + url) # ← silencieux, et exploitableこのガードは正しいSSRF防御であり、文字列にまだ残っているシェルのメタ文字については何も言わない。どこでもティントをパージすることは、174の偽陽性の減少と、コマンドインジェクションの死角を購入した。
したがって、エンジンが運ぶ区別:値を制約するガード(リテラルのホワイトリスト、列挙する fullmatch)は、それをすべてに対してホワイトリスト化する。宛先を証明するガード(ホストが許可されている、解決されたアドレスがパブリックである、パスが封じ込められている)は、関連するシンクファミリーに対してのみ有効である。bleach.clean も同様で、HTMLを中和し、x; rm -rf / を無傷のままにする。
4つの敵対的プローブがテストスイートにあり、すべて正しくフラグする。これらの穴の1つを再び開く将来の「改善」は、名前付きテストを壊す。
残りの沈黙には2つの原因があり、thot bench はそれらを分離する。なぜなら、それらは2つの異なる作業だからだ:
règle muette — elle existe et ne matche jamais : elle a un motif à élargir
aucune règle pour la classe : il y en a une à écrireこの区別が目標の順序を決定する——それがないと、無言のカテゴリはJ = 0で完全に同点になり、ソートはアルファベット順にフォールバックする。
融合、それが何かを変えるところ
Cascade.turn は1つのエージェントを選んで呼び出す。最初のエージェントがエラーを返した場合のみ、もう1つを探しに行く。このようなターンは、構造上、2つのうちの良い方に上限がある。失うことはあっても、得ることは決してない。agent_apply も同じことをしていた——単数のエンジン。
thot evolve --fused は、同じ問題の異なる半分で、両方を働かせる:
thot bench ~/.thot/bench # où ça fait mal
thot evolve --from-bench --fused \
--corpus ~/.thot/bench --hold-out flask # et on répare, en boucleHermesは測定値を読み、仕様を書く。 彼はどのファイルにも触れない。彼の出力は原因についての主張である。どのルール、どの行、なぜこれらのケースなのか。
Primeは仕様を読み、コードを書く。 コードがそれと矛盾する場合、彼はそれを拒否できると明示的に言われる——ノーと言えない実行者は中継であり、中継は何も追加しない。
どちらも決定しない。 テストスイートはフロアであり、ラベル付きコーパスが評決である。確信を持って適用された誤った仕様はスコアを下げ、バイト単位で取り消される。
順序も恣意的ではない。設計-そして-構築は、接合部で検証される。Primeは、コミットする前にHermesの推論を見る。構築-そして-再読はそれを許可しない——2番目が見るとき、1番目はすでに決定している。
目標は測定から来るのであって、入力された文からではない。これまでループは、人間がすでに疑っていたものだけを追求できた。スコアから構築された目標は、プログラムが自分がどこで弱いかを、自分が選んでいない数字で言うことである——そして同じ数字が、その後、答えが役立ったかどうかを示す。各目標は、失敗したファイルを運ぶ。「xssは0 %だ」と言われたエージェントは推測するしかない。3つの失敗したファイルを与えられたエージェントは、解決すべき問題を持っている。
過学習、そして --hold-out が本当にできること
コーパスでスコアされたループには、不正をする本当の方法が1つだけある:コーパスを学習すること。BenchmarkTest01126 がどのように見えるかに合わせたルールは、スコアを上げ、誰の役にも立たず、外部から見ると本当の進歩と区別がつかない。
--hold-out flask は、メインの数値から1つのスイートを取り出し、それを2番目のガードレールとして保持する。最適化されたスイートを動かすが、見たことのないスイートを動かさない変更は、それが何であるかを語った。両方の数値は ne_baisse_pas として保持される。
その限界、測定されたもの:3つのフレームワークは互いに0.5ポイント以内でスコアする。それはファイルレベルの過学習を捕まえるが、ベンチマークの形状への過学習は捕まえない——生成されたコーパスは生成されたコーパスのままであり、デモコードでのみ役立つルールは3つすべてを通過するだろう。ホールドアウトは不正を可視化する。それはコーパスを代表的にするわけではない。
ループがターンからターンへ保持するものは、~/.thot/evolve-log.jsonl に書かれている。それがなければ、測定値が1ターンでほとんど動かないため、次のターンは同じ最悪のカテゴリを再読し、同じファイルを提示し、そして——合理的に——すでに構築され、測定され、取り消された同じ仕様を受け取る。--rounds 5 は、5回試みられた試行、5倍のコスト、忙しいふりをすることになる。
それはオラクルではない。修正がグリーンで、Jを上げ、それでも悪いままであることがある——それは過学習であり、自動プログラム修復の文献はそれだけを語っている。コーパスは、それに対して進歩したという証拠である。ループは、人間が反対できるように、自分が変更したものを報告する。
Skills — Thotが知っているメソッド
スキルとは、一度書かれたメソッドである。YAMLフロントマターを持つ SKILL.md。これはHermes AgentとPrime Agentのフォーマットである。したがって、2つのうちの1つ用に書かれたスキルは、変更なしでここにロードされ、その逆も同様である。
ThotはHermes Agentの完全なライブラリ(MIT — NOTICE.md を参照)を同梱している:90のメソッドがロードされ、さらに117が利用可能である。
thot skills list # les 91 chargées
thot skills search pentest # y compris la bibliothèque optionnelle
thot skills install ast-grep # activer une optionnelle
thot skills show plan # ce que lirait le modèleロードされたカテゴリ:audit、security、software-development、github、devops、research、mlops、productivity、creative、apple、email、media、note-taking、smart-home、social-media、autonomous-ai-agents。
モデルはskillsツールでそれらを発見する——キーワードを与えない限り名前のインデックスで応答する(200件の説明はカタログではないからだ)——そしてskillで該当するものを読む。セッション中は、/skillsで同じものが表示される。
ここにないツール(delegate_task、browser_navigate…)を引用するインポート済みメソッドは、そのまま提供され、どのツールが欠けていて代わりに何を使うべきかを示すメモが添えられる。ツール呼び出しが移植できなくても、そのアプローチは移植できる。
追加する
~/.thot/skills/<nom>/SKILL.md # partout où tu travailles
<repo>/.thot/skills/<nom>/SKILL.md # versionné avec ce dépôt---
name: ma-méthode
description: Ce qu'elle fait et quand s'en servir.
---
# Ma méthode
Les étapes, dans l'ordre.どちらの配置も受け入れられる:フラットなフォルダ(Prime Agent)か、カテゴリごとにグループ化(Hermes Agent)。既存の名前は組み込みバージョンを置き換える——フォークせずに提供されたメソッドを適応させる手段だ。
監査対象リポジトリが提供するメソッドは最初に分析される
SKILL.mdは指示としてモデルに渡されるテキストだ。Thotが読むリポジトリは、定義上、誰も責任を持たないものだ。敵対的なリポジトリが.thot/skills/x/SKILL.mdを置けば、ブリーフィングの一部を書き込むことになる。
Hermes Agentのガードがここに移植され、リポジトリ由来のすべてに適用される:インジェクション、外部送信、永続化、難読化。
▲ 1 skill(s) fourni(s) par ce dépôt ont été refusés — ils seraient passés
au modèle comme instructions.
pwn curl vers l'extérieur ; accès à ~/.thot ; « ignore previous
instructions »thot skills scan <ディレクトリ>は、要求に応じて同じ質問を投げかける。Thot自身が提供するものは分析されない:それはプログラムがインストールされているからディスク上にあるのであって、リポジトリが要求したからではない。
カスタムコマンド
マークダウンファイルはコマンドだ。文法はPrime Agent、Claude Code、Codexのものと同じ——学ぶべき新しいことは何もない。
---
description: Relire un fichier sans rien modifier.
argument-hint: <chemin>
---
Relis $1 et dis-moi ce qui cloche. Ne modifie rien..thot/commands/revue.mdに置くと、/revue src/app.pyが作成される。置換:$1、$2…、$@、$ARGUMENTS、${@:2}、${@:2:3}。引数が再解釈されることは決してない。リポジトリのコマンドは、そのスキルと同じガードを通過する。
3つが同梱されている:/triage(エントリに名前を付けるか、保留として分類)、/harden(最初に失敗するテスト、次に修正)、/regress(git参照に対する差分監査)。
MCPサーバー
Hermes Agentのカタログ、検証済みサーバー20件:
thot mcp list # le catalogue, et ce qui est déjà connecté
thot mcp show sentry
thot mcp add linearインストールは公式CLIに委任されており、OAuthとトークン更新をすでに備えている——Thotが漏洩させかねない第二の金庫を保持する理由はない。登録済みは承認済みではないこと、そしてどのコマンドが作業を完了させるかを明示的に示す。
モデルのツール
定番——読み取り、書き込み、編集、コマンド実行。すべての書き込みと実行は確認を要求し、これは設定不可だ。
そしてThotだけが持つ4つのツール。無料——モデルではなくマップに問い合わせるからだ:
ツール | 応答 |
| プロジェクトのファイル |
| 関数のファイル、行、パラメータ |
| 誰が何を呼ぶか、エントリポイントまでの距離 |
| ソース→シンクのティントパス |
アカウントモードでは、これら4つはthot.mcp_serverによって公式CLIに提供される——読み取り専用のMCPサーバーで、何も書き込んだり実行したりできない。
モデルがprocess_paymentを誰が呼ぶかを探すとき、グラフに問い合わせて完全な回答を得る——ランダムに3つのファイルをgrepする代わりに。
監査のみモード
分析コアは、モデルなし、ネットワークなし、コストなしでも使用できる:
thot init /chemin/du/repo --owner "Ton Nom" # autorisation, une fois
thot audit /chemin/du/repo --paths # chemins de teinte complets
thot audit . --all # y compris le bruit faible
thot audit . --json --out rapport.json
thot audit . --out rapport.sarif # SARIF 2.1, format déduit du nom
thot audit . --fail-on high # code 1 en CISARIF——既存のチェーンに入る
どのパイプラインも読めないレポートは、単一のターミナルの中だけで生きる。GitHub code scanning、GitLab、Azure DevOps、エディタはすべてSARIF 2.1を読み、Thotの2つのプロパティは他よりも価値がある。
ファインディングの同一性はルール+ファイル+シンボル+本体のフィンガープリントであり、行番号ではない——これはまさにpartialFingerprintsが要求するものだ。行番号で供給されるダッシュボードは、誰かがファイルの先頭にimportを追加するたびにすべてのチケットを再オープンする;これで供給されれば、そうはならない。
そしてティントパスは位置の連続であり、codeFlowsがそれを表現する:読者はツールの言葉を信じる代わりに、ソースからシンクへクリックする。パスのないファインディングはcodeFlowsキーを持たない——空のフローはステップのないティントパスとして表現され、それはパターンマッチではなく壊れた分析として読まれる。
パネルによって反駁されたファインディングは削除されない:正当化されたsuppressions付きで送られる。それを決して見ないダッシュボードは、「誰も見ていない」と「誰かが見て判断した」を区別できない——そして後者がパネルの存在理由のすべてだ。
- run: thot audit . --out thot.sarif
- uses: github/codeql-action/upload-sarif@v3
with: { sarif_file: thot.sarif }支援分析——--deep
決定論的分析は「これらのデータは流れ得るか?」に答える。それは網羅的で、無料で、監査人に判断を依頼する質問ではない。--deepは、それに値する候補だけに対して、高価な質問を投げかける:
thot audit . --deep # 20 pires candidats, 4 en parallèle
thot audit . --deep --budget 50 # plus large
thot audit . --deep --parallel 8 # plus vite意図的に敵対的な2つのパス:
プローブは、危険なポイントに到達する具体的な入力を指名しなければならない。脆弱性クラスに関する一般論ではない——URL、値、効果だ。
反駁は、そのシナリオを受け取り、唯一の使命としてそれを破壊する:事前検証、定数のみを渡す呼び出し元、想定された入力を禁止する型。疑わしい場合は、反駁する。
ファインディングは、同じコードに対する2回目の敵対的読解がそれを殺すことに失敗した場合にのみ生き残る。そのときconfirmedは意味を持つ。
セッション中も同じ:/audit deep。
エンジンは自動的に選択される——公式CLI経由のClaudeアカウントが接続されていればそれ(分析はサブスクリプション上で並列実行される)、そうでなければAPIキー。
監査が読んではならないもの
# .thotignore, à la racine du dépôt
vendor/
*.generated.py
tests/fixtures/組み込みの除外は、あらゆるリポジトリが持つものをカバーする——node_modules、build、.venv。.thotignoreは、そのリポジトリだけが知っているものをカバーする:埋め込まれたドキュメント、生成されたクライアント、意図的に壊されたフィクスチャのディレクトリ。それらを監査してもファインディングは生まれず、ファインディングがあるはずの正確な場所にノイズが生まれるだけだ。
独自のルール
組み込みカタログは標準ライブラリを知っている。チームがsubprocessの周りに書いたラッパー、サービスが消費するキュー、自社で値を安全にするバリデータは知らない。それを伝える場所がなければ、実際のシステムの監査は毎回同じ3箇所で間違える。
# <repo>/.thot/rules/team.yaml — versionné avec le code
# ~/.thot/rules/*.yaml — ce que tu sais, partout où tu travailles
sinks:
- id: sink.team.run_shell
patterns: [run_shell, shellutil.run_shell]
impact: critical
description: Wrapper shell interne (shell=True)
match_mode: bare # qualified | method | bare | prefix
sources:
- id: source.queue
patterns: [msg.payload]
description: File de messages
match_mode: prefix # couvre msg.payload.decode(...)
sanitizers: [validate_host, team.escape]同じファイルがjs:キーの下でJavaScriptルールを保持する——チームのラッパーは通常両方の言語に存在し、宣言を分離することは、片方の半分が陳腐化する方法だ。
js:
sinks:
- id: sink.js.team
names: [runShell, sh] # comparés au dernier segment, ou qualifiés
impact: critical
description: Notre wrapper shell
needs: [child_process] # ne se déclenche que si le fichier l'importe
sources:
- id: source.js.queue
patterns: [job.payload]
description: File de messages
sanitizers: [escapeArg]モデルが要求するものは信頼できない入力である
ソースは式だ——sys.argv、os.environ。これは起動するプログラムをカバーし、呼び出すプログラムを見逃す:エージェントのツールは、モデルが要求したものからレジストリが埋める名前付きパラメータで信頼できない入力を受け取り、本体のどこにも式は現れない。
これをモデル化しないことの測定コスト:1日午後のSSRF 4件、すべてツール引数で到達可能、ティントでは1件も見つからず——パターンルールで見つかった。パターンルールは形を認識し、何も証明しない。
entry_sources:
- id: entry.tool
patterns: [tools.image_gen] # les fonctions qu'un registre appelle
parameters: [args] # facultatif : lesquels de leurs paramètres
description: Arguments remplis par le modèle
match_mode: prefixデフォルトでは空、意図的に:レジストリがどの関数を呼ぶかはリポジトリに関する事実であり、推測すればすべてのプログラムのすべてのパラメータの下にソースを置くことになる。Hermesで測定した両極端:pluginsとtoolsパッケージを指名するルールは19の証明済みパスを明らかにし、そのうちいくつかは過剰近似だった(ヘルパーが設定から受け取るbase_urlは信頼できないわけではない);argsパラメータを指名するルールはゼロを明らかにする——Hermesのハンドラは名前付きパラメータを取り、辞書ではないからだ。正しいルールは実際のエントリポイントを指名する——そしてそれを知っているのはその作者だけだ。
組み込みのidを再利用するルールはそれを置き換える——チームが意図的に受け入れたシンクを、Thotにパッチを当てずに劣化させる手段だ。不正な形式のファイルは、ファインディングの欠如を信じさせる代わりに、ファイル名と問題のキーを指名して監査を停止する。
抑制
抑制は、どのツールも再読しない唯一のセキュリティに関する主張だ——このツールも、構造上、含まれる。# nosec、# noqa: S310、// eslint-disable … security/…:コードに関する主張であり、一度書かれ、それが記述していた呼び出し元よりも長生きする。
同じ監査の中で2回、ここではそれは誤りだった:
抑制 | 主張していたこと | 実際に真実だったこと |
| スキームは制御されている |
|
| URLは設定からのもの | 呼び出し元の1つがツール引数、つまりモデルからそれを読む |
したがってThotはそれらをクラスとして、LOWで、パターンを横に添えて報告する。ファインディングは「この行は危険だ」とは言わない:「それが免除された理由を誰も再読していない」と言う。--deepパスでは、パターンがまだ成立するかを検証するエージェントがそれを行う。
Pythonでは、パターンではなく実際のコメントトークンが読まれる——正規表現はコメント内の# nosecとdocstring内で引用された同じテキストを区別できず、このモジュールのdocstringは2つを引用している。
この監査がフラグを立てた行に置かれた抑制は、同じオブジェクトではない:それは生きたファインディングと矛盾する主張であり、同じ行を読んで別の結論に達した誰かによって書かれたものだ。それは一段階引き上げられ、その旨が示される。Hermesで測定:45件中7件——そしてその日に読まれた抑制のうち3つは誤りだった。
測定:Thotで0、Primeで0、Hermesで45。
キャリブレーション
精度は検出と同じくらい重要だ。意図的に非報告:
shell=Trueなしのsubprocess.run(cmd)——コマンドを読むシェルはない。cursor.execute("… ?", params)——リテラルクエリ、バインドされたパラメータ。int()、shlex.quote()、os.path.basename()、html.escape()を通過する値——これらの呼び出しは汚染チェーンを断つ。どのエントリポイントも到達しない欠陥は自動的に劣化される——ただしエントリポイントが見つかった場合のみ。まったくない場合、スコープは不明であり、ゼロではなく、その無知の上に何も埋められない。
payload.get(...)はrequests.get(...)ではない。
桁のオーダー、Hermes Agent(Pythonファイル4,457件)で測定:98秒、ファインディング365件、うちhigh 25件——メモリ適用後、デフォルトしきい値を超えるのは3件。
引数が埋めるパラメータ
1つのパラメータがシンクに到達するヘルパーは、渡されるすべてを危険にするわけではない。しかしエンジンは、引数がどこに着地するかを見ずに、呼び出し元をcalleeのシンクのセット全体と照合していた:
def helper(safe, cmd):
os.system(cmd) # seul `cmd` atteint le shell
helper(sys.argv[1], "ls") # la donnée va dans `safe` — et c'était rapporté位置は現在、呼び出しサイトで読まれ、名前付き引数には名前が読まれる。JavaScriptエンジンはすでに独自にそれをやっていた。
実行が可能になった後の測定:Thotとhermes/toolsの分析で要求された83,238の解決のうち、90%が単一のパラメータを指定し、9.8%はどれも指定しない;0.1%は未解決のまま(f(*rest)、f(**options))で、広い回答を保持する。calleeは平均2.68パラメータを提供したため、検索空間のほぼ3分の2が消える——hermes/toolsの分析は11.4秒から9.5秒に短縮される。
一方、findings の数については:変化なし。Thot、prime、hermes/tools は前後でまったく同じ 151 件の候補を返し、そのうち発明されたものはゼロ — 安全性の性質は実地で成立している。4 つのティント経路が短くなるだけで、それ以上はない。上記の修正された形式は実在し、テストがそれを証明しているが、測定された 3 つのツリーのいずれでも発生しない。この修正が買うのは速度とより正確な経路であり、ノイズの削減ではない。
2 つの形式は何も語らない:helper(*args) は未知の数の値を広げ、helper(**options) は名前を 1 つも指定しない。そこでは、エンジンは以前と同じ広い回答を維持する — 保持される集合は常に以前の集合に含まれるため、絞り込みは finding を削除するだけで、新たに発明することは決してない。
レシーバーは呼び出しの構文ではなく、callee のシグネチャに基づいてスキップされる:Runner().go(x) はドットなしの go に解決され、Cls.m(obj, x) も obj.m(x) もどちらも属性である。メソッドはほとんどの場合バインドされて呼び出されるため、パラメータの先頭にある self が決定する — 非バインド呼び出しだけが 1 段階短く読まれる唯一の形式である。
グラフが追跡できないもの
分析が解決しない経路によって到達される欠陥 — ディスパッチテーブルに格納されたハンドラ、デコレートされたビュー、型が不明な変数に対する呼び出し — は、到達不能な欠陥ではない。Thot はこの 2 つを区別する:
HANDLERS = {"run": run_command} # aucun appel : le graphe ne voit rien
@app.route("/ping") # enregistré à l'import par le décorateur
sandbox.run("pytest") # plusieurs `run` répondent à ce nom3 つのケースすべてでスコープは不明であり、ゼロではない。finding は埋もれる代わりに軽いペナルティを保持する。Hermes では:同じ 365 件の findings だが、60 件が 1 段階上がる。誰も呼び出さずかつ誰も言及しない関数は、正しく減点されたままである — そうでなければフィルタはフィルタでなくなる。
制限
ファイルをまたぐティントは Python 専用である:JavaScript と TypeScript はインデックス化され、関数本体と同一ファイル内のヘルパーまで追跡され、解決された呼び出しグラフがないためそこで止まる — 上の表が行ごとに示している。パターンによるルールは、どこにでも適用される。
--deep なしでは、各 finding は PLAUSIBLE である:静的に検出され、まだ実行によって証明されていない。--deep を使用すると、confirmed の finding は反対の反駁を生き延びた — これはまだ実行の証明ではなく、repro によってもたらされる。そして、finding がないことは欠陥がないことの証明ではない:動的ディスパッチ、リフレクション、メタプログラミングは分析から逃れる。
セッション内の全文検索は、fts5 が rowid を遡れない SQLite では一定コストでなくなる:エンジンはそこで 20 件で打ち切る代わりに、一致するもの全体をソートする。CPython 3.12 が搭載するもので測定 — コーパスを 5 倍にすると 6,588 命令に対して 27,443 命令、能力のあるエンジンは 2,215 から 2,698 のままである。テストがこれを検証し、許可しない場合はバージョンを指名する。
開発
cd thot
uv run pytest -q編集可能モードでインストール:ソースコードが即座に有効になる。一方、pyproject.toml が変更された場合(新しい依存関係)、uv tool install --editable --from . thot --force を再実行する必要がある。
決定論的カーネル(codemap、taint、scope、scoring、store、report)はどのエージェントにも依存せず、ネットワークに触れない — テストがこれを検証し、変更があればスイートを失敗させる。
仕様と計画:docs/superpowers/。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Remote MCP for A2A dependency inspector MCP, structured receipts, audit logs, and reviewer-ready evi
Static MCP manifest and tool-policy security preflight with signed input-redacted receipts
A paid remote MCP for CodeG, built to return verdicts, receipts, usage logs, and audit-ready JSON.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/nobodyohm-web/thot'
If you have feedback or need assistance with the MCP directory API, please join our Discord server