AI コーディングエージェントの memory:保存は簡単なほうの半分
先週の Harness の記事では実際のセッションブリーフィングをお見せしましたが、その中の 1 行が、ほかのどの行よりも仕事をしていました:
- **MCP Server** [PITFALL] (claude-code/vincent, 1 day ago): every new ID argument
name must be added to idArgumentResolvers in authz.go, or the cross-org check
silently skips it.
これを読んだエージェントは、前のエージェントが失った午後をまるごと節約できます。よいことです。では、これを 6 か月分だけ古くしてみてください。まったく同じ文が、まったく同じ自信ありげな調子で、その間に 2 人が書き直したファイルを扱っているエージェントに配られます。この行の見た目は何も変わりません。エージェントにはそれを見分ける方法がなく、あなたにもありません。
これがコーディングエージェントの memory における本当の問題で、しかもほとんどのツールが作っているのはこの部分ではありません。書き留めることは、簡単なほうの半分です。
なぜノートの山ではその問いに答えられないのか
今日のエージェント memory によくある形は、エージェントが追記していく markdown ファイルと、書き込み先のベクターストアです。どちらも保存はうまくやります。どちらも取り出しもそれなりにできます。しかしどちらも、あるノートの足元が動いたことを教えてはくれません。どちらも、そのノートが構造的にいったい何についてのものなのかを知らないからです。ベクターストアは、そのノートが「gateway」や「headers」という語の近くにあることは知っています。しかし ApiGateway があなたのシステムの container であること、それにソースパスがあること、そしてそのパスのコードが 3 週間前からドキュメント化されたモデルと一致しなくなったことは知りません。
アーキテクチャモデルは、その 3 つすべてを知っています。それが memory をモデルの隣に置くべき理由のすべてであり、この記事の中で他社製品が 1 スプリントでは真似できない唯一の部分です。
memory は今、Archyl のすべてのプランで使えます。何をするものなのかを説明します。
memory は会話ではなく要素に紐づく
memory とは、note、convention、pitfall のいずれかの型を持つ事実で、C4 要素またはプロジェクト全体に紐づきます。エージェントは MCP 経由で書き込み、人は Agent Hub か、ダイアグラム上の任意の要素の詳細パネルから書きます。
▶ remember(projectId: …, element: "ApiGateway", kind: "pitfall",
content: "The gateway strips custom headers longer than 8KB — payloads must go in the body.")
4 つめの種類として session_outcome があり、ワークセッションが終わるときに自動的に書かれます。8 つのリースを保持していたセッションが生むのは、8 つの要素に紐づいた 1 つの memory であって、同じ段落の 8 つのコピーではありません。この形は取り出しの側で効いてきます。そのうちのどれか 1 つの要素について尋ねたエージェントは、その結果を 1 回だけ受け取ります。セッションがたまたま 8 つのものに触れたというだけで、同じ要約を 8 回読み返すことはありません。
memory の本文とタイトルは保存時に暗号化されています。プロダクト内の他のすべての機密コンテンツ列と同じです。
recall は共通の部分文字列ではなく意味で順位をつける
recall は意味的な類似度と語の重なりを 0.55 対 0.45 の重みで混ぜます。「rate limiting」について尋ねたエージェントは、誰かが「throttling」について書いたノートを受け取ります。単語一致の検索が取りこぼし、同僚なら決して取りこぼさない、まさにその種のケースです。
ベクトルは設計としてベストエフォートです。AI プロバイダー(OpenAI 互換または Ollama)が設定されていなければベクトルは存在せず、スコアリングは以前の挙動どおり純粋に字句的なままになります。壊れるのではなく劣化する、という作りで、プロバイダーなしでセルフホストする場合にはこれが効いてきます。そしてプロバイダーが存在しなかった時期に書かれた memory も、永遠に二流のままではありません。プロバイダーを設定した時点で、バックグラウンドワーカーがそれらのベクトルを埋め戻します。
同じ事実を二度書くと、それは確認になる
プロジェクトがすでに知っていることを言い直しても、2 つめのコピーはできません。コサイン類似度が 0.94 を超えると、その書き込みは代わりに既存の memory を確認し、レスポンスには deduplicated: true が返ります。エージェントが自分の学んだことを再度主張するのは、ノイズではなく証拠です。
0.82 から 0.94 の間が面白い帯域です。近いけれども、同じ事実ではない。これらは保存され、近い一致は similarTo として返ってきます。だから書き手は、まだ生きていてまだ配られている memory に黙って矛盾させるのではなく、意図的に remember(supersedes: "Old title") を呼ぶことができます。
memory は使われ方から学ぶ
すべての recall は、どの memory をどのセッションに配ったかを記録します。セッションが終わるとき、usedMemories が実際に頼りにしたものを名指しします。
この 2 つのシグナルは、意図的に同じ重みにはしていません。memory を配られたことは状況証拠です。使ったと言うことは証言です。だから memory の順位を押し上げるのは引用だけで、それも対数スケールで、1.8x が上限です。人気のある memory が、それを訂正するより新しい memory を埋もれさせられないようにするためです。5 つのセッションに配られて 1 度も引用されなかった memory は 0.75 の乗数を受け取り、ノイズとして扱われます。
扱われる、であって、削除される、ではありません。memory の中のものがヒューリスティックによって取り除かれることは決してありません。無視された memory はインプレッション数とともにレビューキューに入り、人が判断します。この機能全体を貫いているのは同じ原則です:訂正はするが、消しはしない。
memory にはライフサイクルがある
鮮度は、その memory が最後に真だと分かっていた時点、つまり作成時か直近の確認時から、半減期 45 日で減衰します。confirm_memory はその時計をリセットし、確認回数を 1 つ増やします。remember(supersedes: …) は変わってしまった事実を置き換えます。古いバージョンは取り出しの対象からは外れますが、履歴とグラフには残るので、去年プロジェクトが何を信じていたかは今でも見られます。
その上に種類ごとの重みが乗り、これははっきりと意見を持っています:pitfall は 3.0、convention は 2.0、素の note は 1.5、session outcome は 1.0。これからコードを変えようとしているエージェントにとっては、「これはあなたに噛みつくぞ」が「こういうことがありました」に勝ちます。
memory を実際に無効にするのはドリフト
ここまでは、まともな帳簿づけです。この節こそが、memory がアーキテクチャツールに属する理由です。
時間は真実の代理指標としては弱いものです。サービス境界の仕組みについて 2 年前に書かれた convention は、おそらく今も正しい。先月書かれたノートでも、その後書き直されたファイルについてのものなら、おそらく間違っています。減衰はこの 2 つを同じに扱います。時計しか持っていないからです。
memory を本当に怪しくするのは、その要素の裏にあるコードが変わることです。Archyl はすでにそれを、決定論的に計算しています。ドリフトスコアがドキュメント化されたモデルとリポジトリを突き合わせ、もう一致しない要素を名指しします。UI から、API から、あるいは drift-score の GitHub Action で毎回のプッシュごとに実行できます。memory は今、それに配線されました。
ドリフトが同期の外れた要素を見つけると、その要素に紐づくすべての memory に、それが起きた時刻のスタンプが押されます。そのスタンプより前に最後の確認がされた memory は、その後に足元が動いてしまった何かを記述しています。ここから 3 つのことが起こります:
- ランキングで 0.6 の乗数によって降格されます。降格であって、非表示ではありません。それがその要素について誰かが書いた唯一のものである可能性があり、隠すことは、警告つきで配ることよりも悪いからです。
- 人間向けのレビューキューに現れます。
- エージェントはブリーフィングの中で、メタデータではなく言葉として警告を読みます:
- **ApiGateway** [PITFALL] [VERIFY — the element drifted since this was written]
(claude-code/sarah, 96 days ago): the gateway strips custom headers longer than 8KB.
memory を再確認するとそのフラグは消えます。確認は、ドリフトの問いに直接答えているからです:誰かが見に行って、それはまだ成り立っていた、と。
この仕組みの両方の半分が、同じプロダクトの中にあります。知識がここにあり、それを覆しうるモデル対コードの比較もここにあります。チャットクライアントにボルト留めされた memory レイヤーは、最初の半分だけを持っていて、2 つめを手に入れる手段を持ちません。
memory どうしがリンクする
memory にタイトルを付けると、アドレス指定できるようになります。他のどの memory も、その内容の中で [[Title]] と書いて参照できます。Obsidian 方式です。同じ構文は C4 要素を名前で解決し([[ApiGateway]])、決定も解決します([[ADR-17]])。まだ存在しないタイトルへのリンクは保留のまま残り、誰かがその memory を書いた瞬間に自動的に繋がります。
リンクは読むためだけのものではありません。recall はリンクをたどります。上位の一致はリンク先の隣人を引き連れてきて、via と印がつくので、何がそれを連れてきたのかが分かります。gateway についての pitfall が、その境界が存在する理由を説明する ADR にリンクしていれば、理屈がくっついた状態で届きます。
knowledge map と、捨てたグラフ
memory パネルの最初のバージョンはノードリンクのグラフでした。ちゃんと描画され、クラスタも作り、いかにもスクリーンショットを撮りたくなる見た目でした。それが答えていたのは「どの memory がどの memory にリンクしているか」であり、それは誰も尋ねていない問いでした。
人が知る必要があるのは、自分たちのアーキテクチャのどの部分をプロジェクトが理解していて、どの部分について誰も一言も書いていないのか、です。そこで置き換えました。パネルは今、C4 要素ごとに 1 つのセルを表示します:それについて何が分かっているか、その知識はどれくらい新しいか、そこに pitfall がいくつあるか、そして何もない要素については、目に見える空白を。そこから、どんなダッシュボードもこれまで出してくれなかった見出しが生まれます:
3 of 19 elements documented
この一文は、役に立つやり方で居心地が悪い。グラフはそうではありませんでした。
これがやらないこと
意味的な recall には AI プロバイダーが必要です。 OpenAI 互換のエンドポイントもなく Ollama もなければ、ベクトルもなく、ランキングは語の重なりにフォールバックします。このページの他のすべては、それでも動きます。
要素のマッチングは今も字句的です。 memory は意味で順位をつけるようになりました。しかしその前の段階、あなたのタスクがどの要素についてのものかを選ぶ find_relevant_context は、依然として名前・説明・タグ・パスの語の重なりでスコアリングします。「checkout」についてのタスクは、今も OrderProcessor という component を浮かび上がらせません。これは多くのエージェント、ひとつのアーキテクチャでも限界として挙げましたが、今も変わっていません。
有用性のシグナルは、エージェントが使ったものを申告した場合にしか存在しません。 archyl-harness スキルは、エージェントに sessionId を recall に渡すことと、終わるときに usedMemories を名指しすることを教えます。強制するものは何もありません。スキルなしで接続したエージェントはインプレッションだけを生み、引用はゼロになります。それは、誰も役に立つと思わなかった memory とまったく同じに見えます。
memory のスコープはプロジェクト単位です。 組織全体に効く convention は、それを必要とする各プロジェクトに書き込まなければなりません。これが次に直すものです。
そして全体としての正直な但し書き:memory は出たばかりです。採用の数字もなければ、ベンチマークもなく、これで何かが節約できたと言ってくれる顧客もいません。ここまでに書いたのはコードが実際にやることであり、その一つひとつをあなた自身のプロジェクトで確かめられます。
どこから始めるか
すでに Harness を動かしているなら、memory はもうオンになっています。remember、recall、confirm_memory は、coding プロファイルの 16 個の tool のうちの 3 つです。Claude Code プラグインのバージョン 0.8.0 が、ランキングが依存する 2 つの習慣をエージェントに教えてくれる部分です:sessionId を recall に渡すことと、終わるときに使ったものを名指しすること。
最初にやる価値があるのは、memory を書くことではありません。knowledge map を開いて、カバレッジの行を読むことです。そこに表示された割合が何であれ、それが、それを理解している人が休暇に出かけても生き残るあなたのアーキテクチャの割合です。見る前に数字を当ててみて、それから見てください。
その次に、いちばんトラフィックが多くていちばん書かれていない要素を 1 つ選び、新入りの初日に伝えるであろう落とし穴を書いてください。それが次のエージェントに必要な memory であり、誰かがそれを打ち込むまでは、どれだけ取り出しを頑張っても見つかりません。
memory は Archyl Harness の一部です:ワークセッション、プリフライトゲート、Guard フック、そして Fleet console。プラグイン、スキル、Guard フックと GitHub Actions はオープンソースで、完全なリファレンスは Harness ガイドにあります。関連記事:ワークセッション、多くのエージェント、ひとつのアーキテクチャ、なぜあなたのエージェントにはルールファイルがあってモデルがないのか。