|
| 1 | +--- |
| 2 | +name: Neotoma Harness Hooks Integration |
| 3 | +overview: Extract Neotoma's core operations into an importable client library and build native hook/middleware adapters for programmatic agent frameworks (Claude Agent SDK, OpenAI Agents SDK, Vercel AI SDK, LangChain/LangGraph), replacing MCP as the integration mechanism for these harnesses. |
| 4 | +todos: |
| 5 | + - id: extract-core-ops |
| 6 | + content: Extract executeTool operations from src/server.ts into importable src/core/operations.ts module |
| 7 | + status: pending |
| 8 | + - id: ts-client |
| 9 | + content: Create @neotoma/client TypeScript package with HTTP and local transports |
| 10 | + status: pending |
| 11 | + - id: py-client |
| 12 | + content: Create neotoma-client Python package (HTTP transport, aligned with openapi.yaml) |
| 13 | + status: pending |
| 14 | + - id: vercel-adapter |
| 15 | + content: Build @neotoma/vercel-ai middleware adapter (transformParams + wrapGenerate) |
| 16 | + status: pending |
| 17 | + - id: claude-sdk-adapter |
| 18 | + content: Build @neotoma/claude-agent-sdk hooks adapter (SessionStart, PostToolUse, Stop) |
| 19 | + status: pending |
| 20 | + - id: openai-agents-adapter |
| 21 | + content: Build neotoma-openai-agents Python RunHooks adapter |
| 22 | + status: pending |
| 23 | + - id: langchain-adapter |
| 24 | + content: Build @neotoma/langchain callback handler and optional Store adapter |
| 25 | + status: pending |
| 26 | + - id: docs-and-site |
| 27 | + content: Add hook integration guides and update site subpages to show hooks as primary path for programmatic SDKs |
| 28 | + status: pending |
| 29 | +isProject: false |
| 30 | +--- |
| 31 | + |
| 32 | +# Neotoma Harness Hooks Integration |
| 33 | + |
| 34 | +## Problem |
| 35 | + |
| 36 | +Neotoma currently integrates with all harnesses exclusively via MCP (Model Context Protocol). For programmatic agent SDKs -- where developers write code and control the agent loop -- MCP adds unnecessary protocol overhead and configuration friction. These frameworks have native hook/middleware/callback systems designed for exactly this kind of integration. |
| 37 | + |
| 38 | +## Target Frameworks and Their Hook Surfaces |
| 39 | + |
| 40 | +- **Vercel AI SDK (TypeScript):** `wrapLanguageModel` middleware with `transformParams`, `wrapGenerate`, `wrapStream`; plus `onStepFinish`/`onFinish` callbacks |
| 41 | +- **Claude Agent SDK (TypeScript + Python):** `PreToolUse`, `PostToolUse`, `SessionStart`, `SessionEnd`, `Stop`, `UserPromptSubmit` hooks via `ClaudeAgentOptions.hooks` |
| 42 | +- **OpenAI Agents SDK (Python):** `RunHooks` / `AgentHooks` with `on_agent_start/end`, `on_llm_start/end`, `on_tool_start/end`, `on_handoff` |
| 43 | +- **LangChain/LangGraph (TypeScript + Python):** `BaseCallbackHandler` with `on_llm_start/end`, `on_tool_start/end`; plus `Store` interface for long-term memory |
| 44 | + |
| 45 | +## Language Recommendation |
| 46 | + |
| 47 | +**TypeScript first** (matches Neotoma codebase, covers Vercel AI SDK + Claude Agent SDK TS + LangChain.js). **Python second** (covers OpenAI Agents SDK + Claude Agent SDK Python + LangGraph Python). The client library needs both from the start since OpenAI Agents SDK is Python-primary. |
| 48 | + |
| 49 | +## Architecture |
| 50 | + |
| 51 | +```mermaid |
| 52 | +flowchart TD |
| 53 | + subgraph frameworks [Agent Frameworks] |
| 54 | + VercelAI[Vercel AI SDK] |
| 55 | + ClaudeSDK[Claude Agent SDK] |
| 56 | + OpenAISDK[OpenAI Agents SDK] |
| 57 | + LangChain[LangChain/LangGraph] |
| 58 | + end |
| 59 | +
|
| 60 | + subgraph adapters [Hook Adapters] |
| 61 | + VercelAdapter["@neotoma/vercel-ai"] |
| 62 | + ClaudeAdapter["@neotoma/claude-agent-sdk"] |
| 63 | + OpenAIAdapter["neotoma-openai-agents"] |
| 64 | + LangChainAdapter["@neotoma/langchain"] |
| 65 | + end |
| 66 | +
|
| 67 | + subgraph client [Client Library] |
| 68 | + TSClient["@neotoma/client (TS)"] |
| 69 | + PyClient["neotoma-client (Python)"] |
| 70 | + end |
| 71 | +
|
| 72 | + subgraph transport [Transport] |
| 73 | + LocalImport["Local import (in-process)"] |
| 74 | + HTTP["REST API (HTTP)"] |
| 75 | + end |
| 76 | +
|
| 77 | + subgraph neotoma [Neotoma Core] |
| 78 | + CoreAPI["Exported core operations"] |
| 79 | + Server["API server (src/actions.ts)"] |
| 80 | + end |
| 81 | +
|
| 82 | + VercelAI --> VercelAdapter |
| 83 | + ClaudeSDK --> ClaudeAdapter |
| 84 | + OpenAISDK --> OpenAIAdapter |
| 85 | + LangChain --> LangChainAdapter |
| 86 | +
|
| 87 | + VercelAdapter --> TSClient |
| 88 | + ClaudeAdapter --> TSClient |
| 89 | + OpenAIAdapter --> PyClient |
| 90 | + LangChainAdapter --> TSClient |
| 91 | + LangChainAdapter --> PyClient |
| 92 | +
|
| 93 | + TSClient --> LocalImport |
| 94 | + TSClient --> HTTP |
| 95 | + PyClient --> HTTP |
| 96 | +
|
| 97 | + LocalImport --> CoreAPI |
| 98 | + HTTP --> Server |
| 99 | + Server --> CoreAPI |
| 100 | +``` |
| 101 | + |
| 102 | +## Key Files to Change / Create |
| 103 | + |
| 104 | +### Phase 1: Core Client Library |
| 105 | + |
| 106 | +**Problem:** Neotoma's domain logic is only accessible via MCP (`src/server.ts` `executeTool`) or CLI. No importable API exists. |
| 107 | + |
| 108 | +- **Extract core operations** from [`src/server.ts`](src/server.ts) `executeTool` (line ~1714) into a standalone module (e.g. `src/core/operations.ts`) that can be imported directly without MCP protocol |
| 109 | +- **Create `@neotoma/client` package** in `packages/client/` -- a TypeScript client that can use either: |
| 110 | + - **Local transport:** Direct import of core operations (in-process, no HTTP) |
| 111 | + - **HTTP transport:** REST calls to the API server via `openapi.yaml` contract |
| 112 | +- **Create `neotoma-client` Python package** in `packages/client-python/` -- HTTP-only client generated from or aligned with `openapi.yaml` |
| 113 | +- **Update `package.json` exports** to expose the core operations module |
| 114 | + |
| 115 | +### Phase 2: Framework Hook Adapters (TypeScript first) |
| 116 | + |
| 117 | +Each adapter is a thin package that depends on `@neotoma/client` and implements the framework's native hook interface. |
| 118 | + |
| 119 | +**`@neotoma/vercel-ai`** (in `packages/vercel-ai/`): |
| 120 | +- Implements `LanguageModelV3Middleware` with: |
| 121 | + - `transformParams`: retrieves relevant entities from Neotoma and injects as system prompt context |
| 122 | + - `wrapGenerate` / `wrapStream`: stores conversation turns and extracts entities after each generation |
| 123 | +- Exports `createNeotomaMiddleware(config)` and `onStepFinish` / `onFinish` callback helpers |
| 124 | + |
| 125 | +**`@neotoma/claude-agent-sdk`** (in `packages/claude-agent-sdk/`): |
| 126 | +- Provides hook functions for `ClaudeAgentOptions.hooks`: |
| 127 | + - `SessionStart`: initializes Neotoma session, retrieves prior context |
| 128 | + - `PostToolUse`: stores tool results as observations with provenance |
| 129 | + - `Stop`: persists final conversation state |
| 130 | +- Exports `createNeotomaHooks(config)` returning a hooks object |
| 131 | + |
| 132 | +**`@neotoma/langchain`** (in `packages/langchain/`): |
| 133 | +- Implements `BaseCallbackHandler` with `on_llm_end` / `on_tool_end` for persistence |
| 134 | +- Optionally implements LangGraph `Store` interface so Neotoma serves as the long-term memory backend |
| 135 | + |
| 136 | +### Phase 3: Python Adapters |
| 137 | + |
| 138 | +**`neotoma-openai-agents`** (in `packages/openai-agents-python/`): |
| 139 | +- Subclasses `RunHooks` with: |
| 140 | + - `on_agent_start`: retrieves context from Neotoma |
| 141 | + - `on_agent_end`: stores final output |
| 142 | + - `on_tool_end`: stores tool results |
| 143 | + - `on_handoff`: records agent handoff provenance |
| 144 | +- Exports `NeotomaRunHooks(client, session_id)` and `NeotomaAgentHooks(client)` |
| 145 | + |
| 146 | +**`neotoma-claude-agent-sdk-python`** (in `packages/claude-agent-sdk-python/`): |
| 147 | +- Same hook pattern as TypeScript but for `claude_agent_sdk` Python package |
| 148 | + |
| 149 | +### Phase 4: Documentation and Site |
| 150 | + |
| 151 | +- Add integration guide docs in `docs/developer/hooks/` for each framework |
| 152 | +- Update existing subpages (e.g. `NeotomaWithClaudeAgentSdkPage.tsx`) to show hooks as the primary integration path (MCP as alternative) |
| 153 | +- Add new subpages for Vercel AI SDK, OpenAI Agents SDK, LangChain if they don't exist |
| 154 | +- Update `docs/developer/mcp_overview.md` to position MCP for IDE tools, hooks for programmatic SDKs |
| 155 | + |
| 156 | +## What Each Hook Does (Across All Frameworks) |
| 157 | + |
| 158 | +Regardless of framework, every Neotoma hook adapter provides these capabilities: |
| 159 | + |
| 160 | +- **Context retrieval:** Before LLM calls, retrieve relevant entities from Neotoma and inject into the prompt/context (replaces the "bounded retrieval" step from MCP instructions) |
| 161 | +- **Turn persistence:** After each agent step/turn, store the conversation as `agent_message` entities with `PART_OF` relationships to a `conversation` entity (replaces the mandatory store-first rule from MCP instructions) |
| 162 | +- **Entity extraction:** Parse agent outputs for mentions of people, tasks, events, etc. and store as structured entities with `REFERS_TO` relationships |
| 163 | +- **Provenance tagging:** Every observation stored includes `data_source` metadata identifying the framework, agent, session, and timestamp |
| 164 | +- **Idempotency:** Use turn-based idempotency keys (`conversation-{id}-{turn}-{ts}`) consistent with existing MCP conventions |
| 165 | + |
| 166 | +## Relationship to MCP |
| 167 | + |
| 168 | +This does NOT replace MCP. The integration matrix becomes: |
| 169 | + |
| 170 | +- **IDE/chat tools (Cursor, Claude Code, ChatGPT, Codex, OpenClaw):** MCP remains the only path -- these are closed applications |
| 171 | +- **Programmatic SDKs (Vercel AI, Claude Agent SDK, OpenAI Agents, LangChain):** Native hooks become the primary recommended path; MCP remains available as fallback |
| 172 | + |
| 173 | +## Monorepo Structure |
| 174 | + |
| 175 | +``` |
| 176 | +packages/ |
| 177 | + client/ # @neotoma/client (TypeScript) |
| 178 | + src/ |
| 179 | + index.ts |
| 180 | + transports/ |
| 181 | + http.ts # REST API transport |
| 182 | + local.ts # In-process import transport |
| 183 | + operations.ts # Typed operation wrappers |
| 184 | + package.json |
| 185 | + client-python/ # neotoma-client (Python) |
| 186 | + neotoma_client/ |
| 187 | + __init__.py |
| 188 | + client.py |
| 189 | + transport.py |
| 190 | + pyproject.toml |
| 191 | + vercel-ai/ # @neotoma/vercel-ai |
| 192 | + src/ |
| 193 | + middleware.ts |
| 194 | + callbacks.ts |
| 195 | + package.json |
| 196 | + claude-agent-sdk/ # @neotoma/claude-agent-sdk (TS) |
| 197 | + src/ |
| 198 | + hooks.ts |
| 199 | + package.json |
| 200 | + openai-agents-python/ # neotoma-openai-agents (Python) |
| 201 | + neotoma_openai_agents/ |
| 202 | + hooks.py |
| 203 | + pyproject.toml |
| 204 | + langchain/ # @neotoma/langchain (TS + Python) |
| 205 | + src/ |
| 206 | + callback_handler.ts |
| 207 | + store.ts |
| 208 | + package.json |
| 209 | +``` |
| 210 | + |
| 211 | +## Risks and Mitigations |
| 212 | + |
| 213 | +- **API stability:** Framework hook APIs may change. Pin to specific SDK versions and document compatibility. |
| 214 | +- **Scope creep:** Start with store/retrieve in hooks; do NOT implement strategy/execution logic in adapters (State Layer boundary). |
| 215 | +- **Duplicate persistence:** If a developer uses both hooks AND MCP, idempotency keys prevent duplicate storage. |
0 commit comments