プロフィール DavidHLPL · RHINE LAB RSS ↗
資料 X-1092 / AIツール

Hindsight 統合メモリアクセス:FastMCP ブリッジと動的マルチプロジェクトルーティング

技術ノート

公開 / DavidHLPL

このページでは、Vectorize Hindsight メモリエンジンを端末エージェント OMP (Oh-My-Pi) と Codex CLI に接続するブリッジ実装と設定規約を記録する。中心となる改善は、**マルチプロジェクト適応型の分離ルーティング(Dynamic Workspace Routing)**と、セッション状態を保持する FastMCP stdio ブリッジである。

範囲と確認(2026-09-08):2026-08-17 snapshot の Hindsight v0.9.1 接続記録。OMP、Codex、Node.js、bridge は版固定が不十分。コードは過去の例で、その修訂は全文・プロトコルの静的確認のみ。再起動や現 client 設定の互換検証はしていない。


1. マルチプロジェクト適応型分離

複数プロジェクトを開発するとき、グローバルな単一 Bank(例えば常に ulticode を使う方式)をハードコードすると、異なるコードベースのメモリ、エンティティ、ルールが互いに汚染される。

Git root のディレクトリ名から ulticode、resicache、davidhlp_github_io 等の Bank ID を作る。これはアプリ層の論理分割で、独立 DB・process・アクセス制御としての物理隔離ではない。basename と文字置換だけなので、異なるパスの同名 repo や a.b と a_b は衝突する。必要なら client ごとに異なる HINDSIGHT_BANK_ID を明示し、OMP の実 Bank も照合する。

プロジェクトワークスペース (/path/to/project-a)  ──> Git ルート検出 ──> Bank: project-a ──> Hindsight /mcp/project-a/
プロジェクトワークスペース (/path/to/project-b)  ──> Git ルート検出 ──> Bank: project-b ──> Hindsight /mcp/project-b/

2. 過去の FastMCP ブリッジ例 (~/.hindsight/hindsight-bridge.mjs)

Codex CLI と一部の Agent 子プロセスは stdio パイプ経由で JSON-RPC 通信を行う。一方、Hindsight v0.9.1 が提供するのは HTTP ベースの Streamable FastMCP エンドポイントである。そのため、プロトコル変換と Session ID の状態保持を行う軽量なローカル Node.js ブリッジが必要になる:

#!/usr/bin/env node
/**
 * Dynamic Multi-Project FastMCP Bridge for Hindsight
 * サブディレクトリからでも Git リポジトリルートを解決し、正確なプロジェクト Bank ID を求める。
 */
import readline from "node:readline";
import path from "node:path";
import { execSync } from "node:child_process";
import fs from "node:fs";

function findProjectRoot() {
	try {
		const gitRoot = execSync("git rev-parse --show-toplevel", {
			stdio: ["pipe", "pipe", "ignore"],
			encoding: "utf-8"
		}).trim();
		if (gitRoot && fs.existsSync(gitRoot)) return gitRoot;
	} catch {}

	let curr = process.cwd();
	while (curr && curr !== path.dirname(curr)) {
		if (fs.existsSync(path.join(curr, ".git"))) return curr;
		curr = path.dirname(curr);
	}
	return process.cwd();
}

function getDynamicBankId() {
	if (process.env.HINDSIGHT_BANK_ID?.trim()) {
		return process.env.HINDSIGHT_BANK_ID.trim();
	}
	const root = findProjectRoot();
	const baseName = path.basename(root);
	if (!baseName || baseName === "/" || baseName === "." || baseName === "root") {
		return "default";
	}
	return baseName.toLowerCase().replace(/[^a-z0-9_-]/g, "_");
}

const BANK_ID = getDynamicBankId();
const BASE_URL = process.env.HINDSIGHT_API_BASE_URL || "http://127.0.0.1:8888";
const TARGET_URL = `${BASE_URL.replace(/\/+$/, "")}/mcp/${BANK_ID}/`;

let sessionId = null;

const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
	terminal: false
});

rl.on("line", async (line) => {
	const trimmed = line.trim();
	if (!trimmed) return;
	try {
		const payload = JSON.parse(trimmed);
		const headers = {
			"Content-Type": "application/json",
			Accept: "application/json, text/event-stream"
		};
		if (sessionId) {
			headers["mcp-session-id"] = sessionId;
		}
		const res = await fetch(TARGET_URL, {
			method: "POST",
			headers,
			body: JSON.stringify(payload)
		});

		const returnedSessionId = res.headers.get("mcp-session-id");
		if (returnedSessionId) {
			sessionId = returnedSessionId;
		}

		const contentType = res.headers.get("content-type") || "";
		if (contentType.includes("text/event-stream")) {
			const text = await res.text();
			for (const l of text.split("\n")) {
				if (l.startsWith("data:")) {
					const data = l.slice(5).trim();
					if (data && data !== "[DONE]") {
						process.stdout.write(data + "\n");
					}
				}
			}
		} else {
			const json = await res.json();
			process.stdout.write(JSON.stringify(json) + "\n");
		}
	} catch (err) {
		try {
			const parsed = JSON.parse(trimmed);
			if (parsed.id !== undefined) {
				process.stdout.write(
					JSON.stringify({
						jsonrpc: "2.0",
						id: parsed.id,
						error: {
							code: -32603,
							message: `Hindsight Bridge Error: ${err.message}`
						}
					}) + "\n"
				);
			}
		} catch {}
	}
});

例に残るプロトコルの不足

Session ID 転送と Git root 検出の考え方は残るが、完全な汎用 MCP proxy ではない。SSE 応答全体の終了を待って転送し、完全なイベント境界を扱わず、通知の空応答、並行 handshake、session 失効後の再初期化、交渉後の protocol version header も明示処理しない。MCP 2025-06-18 transport では通知成功は本文なし HTTP 202 を返せ、Streamable HTTP 自体が SSE を扱う。Session ID は server が割り当てた場合に後続転送が必要。実 client でこれらを検証し、一回の tools/list 成功を汎用互換の証明にしない。

3. Agent クライアント設定

パス設定規約:Node プロセスと環境は args のパス内の ~ を自動展開しない。/home/user/ のような絶対パスを使うか、環境変数から注入すること。

1. OMP 設定(~/.omp/agent/config.yml と ~/.omp/agent/mcp.json)

~/.omp/agent/config.yml:

memory:
  backend: hindsight
  hindsight:
    apiUrl: http://127.0.0.1:8888
    scoping: per-project # プロジェクトごとに Bank を自動分離
    autoRecall: true     # セッション開始時にメモリを取得して注入
    autoRetain: true     # セッション終了時にメモリを抽出して保持
    mentalModelsEnabled: true # メンタルモデルを有効化
    mentalModelAutoSeed: true # シードメンタルモデルを自動生成
    recallBudget: mid
    autolearn:
      enabled: true
      autoContinue: true

~/.omp/agent/mcp.json(<USER_HOME> を実際の絶対パスに置き換える):

{
  "mcpServers": {
    "hindsight": {
      "type": "stdio",
      "command": "node",
      "args": ["<USER_HOME>/.hindsight/hindsight-bridge.mjs"]
    }
  }
}

2. Codex 設定(~/.codex/config.toml)

[mcp_servers.hindsight]
command = "node"
args = ["<USER_HOME>/.hindsight/hindsight-bridge.mjs"]

[mcp_servers.hindsight.env]
HINDSIGHT_API_BASE_URL = "http://127.0.0.1:8888"
# HINDSIGHT_BANK_ID はハードコードしない。ブリッジが Git ルートで自動ルーティングする。

4. 検証結果と実測指標

以下は 2026-08-17 raw の一回の書き込み・検索の転記で、再実行ではない。回数、負荷、全版、計時方法がなく、score と 0.059s は性能基準ではない。テスト文も現プロジェクトの設定事実ではない:

[書き込み段階(Codex MCP Bridge -> GPU Fact Extraction)]
書き込み:"Backend uses Java 17 and Spring Boot 3.2.5 with three owner services: auth 9101, admin 9102, app 9103."
抽出結果:3 件の Fact エンティティの抽出に成功し、BAAI/bge-m3 でベクトル索引を作成した。

[クエリ段階(OMP / Codex Recall)]
クエリ:"What port does the auth service use?"
結果:"Backend has three owner services: auth (9101), admin (9102), and app (9103)" にヒットした。
指標:リランカー スコア 0.965、セマンティックスコア 0.668、検索応答時間 0.059s。

5. 証拠と不確実性

  • 出典報告:固定 raw hindsight-local-deployment-and-agent-integration は handshake、tool 発見、一回の検索成功を記録する。完全な状態機械や全 client 互換ではない。
  • 総合:bridge code、両端設定、観測値を Entity 接続記録に整理。
  • 静的に確認可能:Git root と明示 HINDSIGHT_BANK_ID がなければ CWD の basename から Bank を作る。空名、/、.、root の場合だけ default。非 Git ではサブディレクトリによるずれが残る。
  • 未確認:現在の OMP per-project 命名との一致、model・権限・retain/recall 全経路は別途実測が必要。

6. 関連ページ

出典と関連文書

研究記録

  1. 元の文書: src/content/note/ja/hindsight-omp-codex-integration.md
  2. 出典リビジョン: f49953fb0d4bd52a39bf81167b0c4b7dd7d78a64
  3. 証拠の状態: 有効

原文の出典 ↗