agent-context-graph 0.2.0__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/.gitignore +3 -7
  2. agent_context_graph-0.3.1/CONTEXT.md +97 -0
  3. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/PKG-INFO +88 -7
  4. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/README.md +84 -6
  5. agent_context_graph-0.3.1/docs/adr/0001-runtime-adapter-terminology.md +3 -0
  6. agent_context_graph-0.3.1/docs/adr/0002-config-file-only-hook-resolution.md +7 -0
  7. agent_context_graph-0.3.1/docs/adr/0003-config-path-override.md +26 -0
  8. agent_context_graph-0.3.1/docs/adr/0004-user-id-in-session-start-event.md +3 -0
  9. agent_context_graph-0.3.1/docs/adr/0005-config-file-covers-llm-key-and-subprocess-env.md +13 -0
  10. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/docs/command-hooks.md +19 -8
  11. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/pyproject.toml +5 -1
  12. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/__init__.py +1 -1
  13. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/_identity.py +156 -32
  14. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/claude.py +13 -9
  15. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/claude_code.py +17 -1
  16. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/codex.py +27 -4
  17. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/cli.py +175 -15
  18. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/runner.py +42 -9
  19. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/runtime_plugin.py +13 -7
  20. agent_context_graph-0.3.1/src/agent_context_graph/mcp_server.py +89 -0
  21. agent_context_graph-0.3.1/src/agent_context_graph/tools.py +95 -0
  22. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_claude_code_adapter.py +58 -8
  23. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_codex_adapter.py +46 -4
  24. agent_context_graph-0.3.1/tests/test_config_cli.py +92 -0
  25. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_hook_cli.py +36 -7
  26. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_identity.py +100 -4
  27. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_link.py +8 -3
  28. agent_context_graph-0.3.1/tests/test_runner_sessions_graph_connector.py +81 -0
  29. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_runtime_plugin.py +1 -1
  30. agent_context_graph-0.3.1/tests/test_tools.py +167 -0
  31. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/LICENSE +0 -0
  32. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/__init__.py +0 -0
  33. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/openai.py +0 -0
  34. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/events.py +0 -0
  35. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/__init__.py +0 -0
  36. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/cli.py +0 -0
  37. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/link.py +0 -0
  38. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/protocols.py +0 -0
  39. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/__init__.py +0 -0
  40. {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_events.py +0 -0
@@ -181,14 +181,10 @@ cython_debug/
181
181
  # Local agent hook configuration
182
182
  /.codex/
183
183
  /.claude/settings.local.json
184
- /AGENTS.md
185
184
  /docs/agents/
186
- /context-graph/CONTEXT-MAP.md
187
- /context-graph/*/CONTEXT.md
188
- /context-graph/docs/adr/
189
- /context-graph/*/docs/adr/
190
185
 
191
186
  # Project specific files
192
187
  /enterprise-context/sic-agent/sic-scrapper/output/*
193
- unstructured2graph/docs/adr/
194
- unstructured2graph/CONTEXT.md
188
+
189
+ # deepeval writes run caches and telemetry here; build artifacts, not source.
190
+ .deepeval/
@@ -0,0 +1,97 @@
1
+ # Agent Context Graph
2
+
3
+ Adapter layer for Context Graph components. Normalizes agent SDK + runtime activity into events, routes to graph connectors.
4
+
5
+ ## Language
6
+
7
+ **Agent Context Graph**:
8
+ Adapter layer normalizing agent SDK + runtime activity into events, routing to graph connectors.
9
+ _Avoid_: Graph storage, skills graph, memory store
10
+
11
+ **Graph Connector**:
12
+ Integration point, owned by a graph component, deciding which normalized events matter to it + persisting their meaning.
13
+ _Avoid_: Adapter, hook, writer
14
+
15
+ **Agent Development SDK**:
16
+ Framework for building agent apps; integrations usually attach via in-process callbacks/hook objects.
17
+ _Avoid_: Runtime hook, command hook
18
+
19
+ **Runtime Hook**:
20
+ Hook emitted by an agent runtime around an already-running session, often via external command + JSON payload.
21
+ _Avoid_: Agent development SDK
22
+
23
+ **Runtime Adapter**:
24
+ Integration point translating one SDK/runtime-hook shape into shared event protocol.
25
+ _Avoid_: Graph connector, storage adapter
26
+
27
+ **Runtime Plugin**:
28
+ Host-specific distribution package installing runtime hooks, skills, commands, setup helpers, other host-native integration files.
29
+ _Avoid_: Graph component, graph connector, storage layer
30
+
31
+ **Codex Plugin**:
32
+ Runtime Plugin for OpenAI Codex; wires Codex lifecycle hooks to an Agent Context Graph runtime adapter entrypoint.
33
+ _Avoid_: Codex graph, skills graph plugin
34
+
35
+ **Claude Code Plugin**:
36
+ Runtime Plugin for Claude Code; wires Claude Code lifecycle hooks to an Agent Context Graph runtime adapter entrypoint.
37
+ _Avoid_: Claude graph, skills graph plugin
38
+
39
+ **Event Protocol**:
40
+ Runtime-agnostic set of agent activity events, emitted by runtime adapters, consumed by graph connectors.
41
+ _Avoid_: Graph event, graph protocol, hook payload, callback data
42
+
43
+ **Agent Session**:
44
+ Runtime-side unit of agent activity grouping related events under shared session identifier.
45
+ _Avoid_: Session node
46
+
47
+ **Hook Configuration**:
48
+ Persistent TOML file supplying identity + connection settings to hook subprocesses. Default path `~/.config/context-graph/config.toml`; `CONTEXT_GRAPH_CONFIG` may select another file. At hook runtime, config values come only from selected file. Env var selects file; never supplies a value from it.
49
+ _Avoid_: env config, runtime config, shell config
50
+
51
+ **Runtime Registration**:
52
+ Python object implementing `RuntimeCLIPlugin`. Package publishes it via `agent_context_graph.runtimes` entry-point group. CLI resolves runtime name through it to find adapter, hook response, hook config, optional initializer.
53
+
54
+ Not a **Runtime Plugin**: plugin installs host-facing files; registration lets Agent Context Graph discover runtime support via `importlib.metadata.entry_points()`. Adding one needs no central registry change.
55
+ _Avoid_: Runtime Plugin (already means distribution package), Runtime Adapter (a Runtime Registration *references* one via `adapter_class`, isn't one)
56
+
57
+ **Tool Registration**:
58
+ Object implementing `Tool` (`tools.py`): a name, a description the model reads, an input schema, the connector whose graph it reads, an optional session-start hint, and `call(arguments, config)`. A graph component publishes it via the `agent_context_graph.tools` entry-point group; `agent-context-graph mcp` serves every registered tool, and the CLI runs one by name. Identity + connection come from **Hook Configuration**, never from tool arguments.
59
+ _Avoid_: MCP tool (the protocol it is served over, not the thing), Graph Connector (writes events; a tool reads)
60
+
61
+ ## Relationships
62
+
63
+ - **Agent Context Graph** belongs to broader **Context Graph** family.
64
+ - **Agent Context Graph** routes events to graph connectors owned by graph components.
65
+ - **Graph Connector** consumes normalized events emitted by **Agent Context Graph**.
66
+ - **Agent Development SDK** integration + **Runtime Hook** integration both use a **Runtime Adapter** to emit same event protocol.
67
+ - **Runtime Plugin** = deployment surface for runtime hooks/setup helpers; not a graph component.
68
+ - **Codex Plugin** installs Codex hook wiring invoking the Codex runtime adapter command.
69
+ - **Claude Code Plugin** installs Claude Code hook wiring invoking the Claude Code runtime adapter command.
70
+ - **Event Protocol** carries agent activity, not graph semantics.
71
+ - **Agent Session** may be persisted as a session node by a graph component; **Event Protocol** only carries the session identifier.
72
+ - Tool/message events carry `agent_name` when runtime identifies a subagent. Agent Context Graph only transports this id; Graph Connectors decide how to use it. Codex adapter doesn't yet handle subagent lifecycle/ids ([#275](https://github.com/memgraph/ai-toolkit/issues/275)).
73
+ - Runtime Plugin's generated command calls `hook run <name>`. CLI resolves name via Runtime Registration; plugin never names an adapter class directly.
74
+ - Built-in Runtime Registrations: `codex`, `claude-code`. Other packages may publish more.
75
+
76
+ ## Example dialogue
77
+
78
+ > **Dev:** "Should Agent Context Graph write the skill usage edge?"
79
+ > **Domain expert:** "No. Agent Context Graph emits the tool event; Skills Graph decides whether that event represents skill usage."
80
+
81
+ > **Dev:** "Are OpenAI Agents SDK and Codex hooks the same kind of integration?"
82
+ > **Domain expert:** "No. OpenAI Agents SDK is for agent development; Codex hooks are runtime hooks. Both become normalized events before graph connectors see them."
83
+
84
+ > **Dev:** "Should the Codex plugin know how to write skill usage?"
85
+ > **Domain expert:** "No. Plugin installs hook wiring. Codex runtime adapter emits events. Skills Graph decides if those events mean skill usage."
86
+
87
+ ## Flagged ambiguities
88
+
89
+ - "graph" = umbrella **Context Graph** family or specific component? Resolved: **Agent Context Graph** = adapter layer only, never persistence.
90
+ - "connector" can sound like generic transport plumbing. Resolved: **Graph Connector** owns graph-specific event interpretation.
91
+ - "adapter" can mean SDK integrations or runtime hooks. Resolved: **Runtime Adapter** = anything translating agent activity into shared event protocol.
92
+ - "SDK adapter" too narrow: Codex command hooks are runtime hooks, not SDK callbacks. Resolved: code/docs use **Runtime Adapter**.
93
+ - "event" shouldn't carry graph nomenclature. Resolved: graph meaning assigned by **Graph Connectors**, not **Event Protocol**.
94
+ - "Session" = activity or graph state? Use **Agent Session** for activity, "session node" for persisted state.
95
+ - "Plugin" can sound like a graph extension. Use **Runtime Plugin** for host-specific distribution; Graph Connectors own graph interpretation.
96
+ - Entry-point discovery = **Runtime Registration**, not a runtime/CLI plugin ([#269](https://github.com/memgraph/ai-toolkit/issues/269)).
97
+ - Code hasn't fully caught up to **Runtime Adapter** terminology: Event Protocol's `source_sdk` field (`events.py`, set by all 4 adapters, read by Actions Graph's connector) still names the rejected term (ADR 0001). Rename to e.g. `source_adapter` tracked, not done.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: agent-context-graph
3
- Version: 0.2.0
3
+ Version: 0.3.1
4
4
  Summary: Connect agent SDKs to context-graph components (actions-graph, skills-graph, etc.)
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -12,9 +12,12 @@ Requires-Python: >=3.10
12
12
  Requires-Dist: memgraph-toolbox>=0.1.11
13
13
  Provides-Extra: claude
14
14
  Requires-Dist: claude-agent-sdk>=0.1.0; extra == 'claude'
15
+ Provides-Extra: mcp
16
+ Requires-Dist: mcp<3,>=1.23.0; extra == 'mcp'
15
17
  Provides-Extra: openai
16
18
  Requires-Dist: openai-agents>=0.1.0; extra == 'openai'
17
19
  Provides-Extra: test
20
+ Requires-Dist: mcp<3,>=1.23.0; extra == 'test'
18
21
  Requires-Dist: pytest-asyncio>=0.24.0; extra == 'test'
19
22
  Requires-Dist: pytest>=9.0.3; extra == 'test'
20
23
  Description-Content-Type: text/markdown
@@ -40,9 +43,11 @@ Runtime plugins are the distribution layer for host-specific hook wiring. They i
40
43
  For command-hook runtimes such as Codex and Claude Code, prefer a user-level tool install:
41
44
 
42
45
  ```bash
43
- uv tool install agent-context-graph --with "skills-graph[agent-context-graph]"
46
+ uv tool install "agent-context-graph[mcp]" --with "skills-graph[agent-context-graph]"
44
47
  ```
45
48
 
49
+ The `mcp` extra is what `agent-context-graph mcp` serves [recall](#recall-memory-for-the-harnesss-model) with.
50
+
46
51
  Or use the plugin bootstrap scripts; they fall back to `uvx` if the tool is not installed yet.
47
52
 
48
53
  For SDK usage inside an application:
@@ -176,7 +181,7 @@ Prerequisites:
176
181
  - Memgraph running and reachable over Bolt. Defaults are `bolt://localhost:7687`, empty user/password, database `memgraph`. If it isn't running locally:
177
182
 
178
183
  ```bash
179
- docker run --rm -p 7687:7687 memgraph/memgraph
184
+ docker run --rm -p 7687:7687 memgraph/memgraph-mage
180
185
  ```
181
186
 
182
187
  **1. Bootstrap all three connectors** (this is what the installed plugin wires into its hooks):
@@ -230,6 +235,8 @@ OK memgraph: reachable
230
235
  OK connector:skills-graph: installed=...; memgraph=reachable
231
236
  OK connector:actions-graph: installed=...; memgraph=reachable
232
237
  OK connector:sessions-graph: installed=...; memgraph=reachable
238
+ OK embeddings: BAAI/bge-small-en-v1.5 (384 dimensions) inside Memgraph
239
+ OK mcp: serves recall
233
240
  OK runtime:claude-code: strict hook smoke passed
234
241
  ```
235
242
 
@@ -248,17 +255,90 @@ url = "bolt://localhost:7687"
248
255
  user = ""
249
256
  password = ""
250
257
  database = "memgraph"
258
+
259
+ [llm]
260
+ openai_api_key = ""
261
+ anthropic_api_key = ""
262
+
263
+ [reconcile]
264
+ auto_reconcile = true
265
+
266
+ [recall]
267
+ embedding_model = "BAAI/bge-small-en-v1.5"
268
+ turns_k = "8"
251
269
  ```
252
270
 
271
+ `[llm]` and `[reconcile]` are only relevant if you enable sessions-graph's
272
+ auto-trigger reconciliation (see
273
+ [sessions-graph § reconciliation](../sessions-graph/README.md#session-reconciliation)).
274
+ `[reconcile]` is omitted entirely from a freshly-bootstrapped file — absent
275
+ means "never configured," distinct from an explicit `auto_reconcile = false`.
276
+ `[recall]` is optional too: without it, recall runs with the widths the
277
+ benchmark measured; see [Recall](#recall-memory-for-the-harnesss-model).
278
+
253
279
  Manage it with:
254
280
 
255
281
  ```bash
256
282
  agent-context-graph config show
257
283
  agent-context-graph config get memgraph.url
258
- agent-context-graph config set <key> <value> # keys: identity.user_id, memgraph.{url,user,password,database}
284
+ agent-context-graph config set <key> <value>
285
+ # keys: identity.user_id, memgraph.{url,user,password,database},
286
+ # llm.{openai_api_key,anthropic_api_key}, reconcile.auto_reconcile,
287
+ # recall.embedding_model
259
288
  ```
260
289
 
261
- Environment variables (`MEMGRAPH_URL`, `MEMGRAPH_USER`, `MEMGRAPH_PASSWORD`, `MEMGRAPH_DATABASE`, `AGENT_CONTEXT_GRAPH_USER_ID`) are consulted **only at bootstrap time** — if set, `bootstrap` persists them into the config file. Exporting them later has no effect on running hooks; use `config set` instead.
290
+ Environment variables (`MEMGRAPH_URL`, `MEMGRAPH_USER`, `MEMGRAPH_PASSWORD`, `MEMGRAPH_DATABASE`, `AGENT_CONTEXT_GRAPH_USER_ID`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) are consulted **only at bootstrap time** — if set, `bootstrap` persists them into the config file. Exporting them later has no effect on running hooks; use `config set` instead.
291
+
292
+ `reconcile.auto_reconcile` is the one exception: `bootstrap` never captures
293
+ `SESSIONS_GRAPH_AUTO_RECONCILE` from the environment, and re-running
294
+ `bootstrap` preserves whatever it's currently set to rather than resetting it.
295
+ Unlike the keys above, nobody has that env var exported for an unrelated
296
+ reason — it's only ever set via `agent-context-graph config set
297
+ reconcile.auto_reconcile true`.
298
+
299
+ ### Recall: memory for the harness's model
300
+
301
+ The hooks write sessions into Memgraph; recall reads them back. With
302
+ sessions-graph installed, `agent-context-graph mcp` serves a `recall(question)`
303
+ tool over stdio MCP, and the Codex and Claude Code plugins bundle that server,
304
+ so installing a plugin is all it takes. The tool returns context, not an answer:
305
+ the dated messages and facts from the user's own sessions that match the
306
+ question, behind a header with the rules for reading them. The harness's model
307
+ answers from those rows.
308
+
309
+ At session start the hook adds one line to the model's context saying the tool
310
+ exists. It never pushes retrieved content; the model calls `recall` when a
311
+ question needs memory.
312
+
313
+ The same search from a shell:
314
+
315
+ ```bash
316
+ agent-context-graph recall "what did we decide about the deploy window?"
317
+ agent-context-graph recall --json "..." # the turns and facts as JSON
318
+ ```
319
+
320
+ Whose memory is searched comes from `identity.user_id` in the config file, never
321
+ from the tool call, so a model can only read its own user's sessions.
322
+ `[recall]` overrides the search's lanes and widths, all optional:
323
+
324
+ | Key | Default | What it sets |
325
+ |---|---|---|
326
+ | `embedding_model` | `BAAI/bge-small-en-v1.5` | The model Memgraph embeds with; set with `config set recall.embedding_model` |
327
+ | `lanes` | all five | Comma-separated subset of `turns,text,entities,facts,user_facts` |
328
+ | `turns_k`, `text_k` | `8`, `8` | Messages found by vector and by text search |
329
+ | `entities_k`, `edges_per_entity` | `15`, `6` | Entities matched, and facts read from each |
330
+ | `facts_k`, `fact_turns_k` | `15`, `8` | Facts matched, and the messages they were read from |
331
+ | `user_fact_types`, `user_facts_k` | `2`, `30` | Relation types gathered whole, for counting questions |
332
+ | `turn_chars` | `1500` | Characters shown per message |
333
+
334
+ Recall needs Memgraph with MAGE (`memgraph/memgraph-mage`) for its vector lanes;
335
+ without it, it answers from text search and says so. `doctor` checks both
336
+ (`embeddings` and `mcp`).
337
+
338
+ **What the model sees.** A tool result carries the rendered text only. Claude
339
+ Code and Codex both show the model a result's `structuredContent` JSON
340
+ *instead of* its text when both are present, and the text is the form recall
341
+ was benchmarked in; the JSON is what `--json` prints.
262
342
 
263
343
  ### OpenAI Codex Plugin
264
344
 
@@ -278,13 +358,14 @@ Plugin source:
278
358
  context-graph/plugins/agent-context-graph-codex
279
359
  ```
280
360
 
281
- Register the public Git-backed marketplace:
361
+ Register the public Git-backed marketplace and install the plugin:
282
362
 
283
363
  ```bash
284
364
  codex plugin marketplace add memgraph/ai-toolkit --sparse .agents/plugins
365
+ codex plugin add context-graph@context-graph-plugins
285
366
  ```
286
367
 
287
- Then install or enable `context-graph` from the Codex plugin UI.
368
+ Both are non-interactive; `codex plugin add` installs and enables the plugin in one step (`codex plugin list --json` confirms `"enabled": true`).
288
369
 
289
370
  Check the installed hook environment with:
290
371
 
@@ -19,9 +19,11 @@ Runtime plugins are the distribution layer for host-specific hook wiring. They i
19
19
  For command-hook runtimes such as Codex and Claude Code, prefer a user-level tool install:
20
20
 
21
21
  ```bash
22
- uv tool install agent-context-graph --with "skills-graph[agent-context-graph]"
22
+ uv tool install "agent-context-graph[mcp]" --with "skills-graph[agent-context-graph]"
23
23
  ```
24
24
 
25
+ The `mcp` extra is what `agent-context-graph mcp` serves [recall](#recall-memory-for-the-harnesss-model) with.
26
+
25
27
  Or use the plugin bootstrap scripts; they fall back to `uvx` if the tool is not installed yet.
26
28
 
27
29
  For SDK usage inside an application:
@@ -155,7 +157,7 @@ Prerequisites:
155
157
  - Memgraph running and reachable over Bolt. Defaults are `bolt://localhost:7687`, empty user/password, database `memgraph`. If it isn't running locally:
156
158
 
157
159
  ```bash
158
- docker run --rm -p 7687:7687 memgraph/memgraph
160
+ docker run --rm -p 7687:7687 memgraph/memgraph-mage
159
161
  ```
160
162
 
161
163
  **1. Bootstrap all three connectors** (this is what the installed plugin wires into its hooks):
@@ -209,6 +211,8 @@ OK memgraph: reachable
209
211
  OK connector:skills-graph: installed=...; memgraph=reachable
210
212
  OK connector:actions-graph: installed=...; memgraph=reachable
211
213
  OK connector:sessions-graph: installed=...; memgraph=reachable
214
+ OK embeddings: BAAI/bge-small-en-v1.5 (384 dimensions) inside Memgraph
215
+ OK mcp: serves recall
212
216
  OK runtime:claude-code: strict hook smoke passed
213
217
  ```
214
218
 
@@ -227,17 +231,90 @@ url = "bolt://localhost:7687"
227
231
  user = ""
228
232
  password = ""
229
233
  database = "memgraph"
234
+
235
+ [llm]
236
+ openai_api_key = ""
237
+ anthropic_api_key = ""
238
+
239
+ [reconcile]
240
+ auto_reconcile = true
241
+
242
+ [recall]
243
+ embedding_model = "BAAI/bge-small-en-v1.5"
244
+ turns_k = "8"
230
245
  ```
231
246
 
247
+ `[llm]` and `[reconcile]` are only relevant if you enable sessions-graph's
248
+ auto-trigger reconciliation (see
249
+ [sessions-graph § reconciliation](../sessions-graph/README.md#session-reconciliation)).
250
+ `[reconcile]` is omitted entirely from a freshly-bootstrapped file — absent
251
+ means "never configured," distinct from an explicit `auto_reconcile = false`.
252
+ `[recall]` is optional too: without it, recall runs with the widths the
253
+ benchmark measured; see [Recall](#recall-memory-for-the-harnesss-model).
254
+
232
255
  Manage it with:
233
256
 
234
257
  ```bash
235
258
  agent-context-graph config show
236
259
  agent-context-graph config get memgraph.url
237
- agent-context-graph config set <key> <value> # keys: identity.user_id, memgraph.{url,user,password,database}
260
+ agent-context-graph config set <key> <value>
261
+ # keys: identity.user_id, memgraph.{url,user,password,database},
262
+ # llm.{openai_api_key,anthropic_api_key}, reconcile.auto_reconcile,
263
+ # recall.embedding_model
238
264
  ```
239
265
 
240
- Environment variables (`MEMGRAPH_URL`, `MEMGRAPH_USER`, `MEMGRAPH_PASSWORD`, `MEMGRAPH_DATABASE`, `AGENT_CONTEXT_GRAPH_USER_ID`) are consulted **only at bootstrap time** — if set, `bootstrap` persists them into the config file. Exporting them later has no effect on running hooks; use `config set` instead.
266
+ Environment variables (`MEMGRAPH_URL`, `MEMGRAPH_USER`, `MEMGRAPH_PASSWORD`, `MEMGRAPH_DATABASE`, `AGENT_CONTEXT_GRAPH_USER_ID`, `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) are consulted **only at bootstrap time** — if set, `bootstrap` persists them into the config file. Exporting them later has no effect on running hooks; use `config set` instead.
267
+
268
+ `reconcile.auto_reconcile` is the one exception: `bootstrap` never captures
269
+ `SESSIONS_GRAPH_AUTO_RECONCILE` from the environment, and re-running
270
+ `bootstrap` preserves whatever it's currently set to rather than resetting it.
271
+ Unlike the keys above, nobody has that env var exported for an unrelated
272
+ reason — it's only ever set via `agent-context-graph config set
273
+ reconcile.auto_reconcile true`.
274
+
275
+ ### Recall: memory for the harness's model
276
+
277
+ The hooks write sessions into Memgraph; recall reads them back. With
278
+ sessions-graph installed, `agent-context-graph mcp` serves a `recall(question)`
279
+ tool over stdio MCP, and the Codex and Claude Code plugins bundle that server,
280
+ so installing a plugin is all it takes. The tool returns context, not an answer:
281
+ the dated messages and facts from the user's own sessions that match the
282
+ question, behind a header with the rules for reading them. The harness's model
283
+ answers from those rows.
284
+
285
+ At session start the hook adds one line to the model's context saying the tool
286
+ exists. It never pushes retrieved content; the model calls `recall` when a
287
+ question needs memory.
288
+
289
+ The same search from a shell:
290
+
291
+ ```bash
292
+ agent-context-graph recall "what did we decide about the deploy window?"
293
+ agent-context-graph recall --json "..." # the turns and facts as JSON
294
+ ```
295
+
296
+ Whose memory is searched comes from `identity.user_id` in the config file, never
297
+ from the tool call, so a model can only read its own user's sessions.
298
+ `[recall]` overrides the search's lanes and widths, all optional:
299
+
300
+ | Key | Default | What it sets |
301
+ |---|---|---|
302
+ | `embedding_model` | `BAAI/bge-small-en-v1.5` | The model Memgraph embeds with; set with `config set recall.embedding_model` |
303
+ | `lanes` | all five | Comma-separated subset of `turns,text,entities,facts,user_facts` |
304
+ | `turns_k`, `text_k` | `8`, `8` | Messages found by vector and by text search |
305
+ | `entities_k`, `edges_per_entity` | `15`, `6` | Entities matched, and facts read from each |
306
+ | `facts_k`, `fact_turns_k` | `15`, `8` | Facts matched, and the messages they were read from |
307
+ | `user_fact_types`, `user_facts_k` | `2`, `30` | Relation types gathered whole, for counting questions |
308
+ | `turn_chars` | `1500` | Characters shown per message |
309
+
310
+ Recall needs Memgraph with MAGE (`memgraph/memgraph-mage`) for its vector lanes;
311
+ without it, it answers from text search and says so. `doctor` checks both
312
+ (`embeddings` and `mcp`).
313
+
314
+ **What the model sees.** A tool result carries the rendered text only. Claude
315
+ Code and Codex both show the model a result's `structuredContent` JSON
316
+ *instead of* its text when both are present, and the text is the form recall
317
+ was benchmarked in; the JSON is what `--json` prints.
241
318
 
242
319
  ### OpenAI Codex Plugin
243
320
 
@@ -257,13 +334,14 @@ Plugin source:
257
334
  context-graph/plugins/agent-context-graph-codex
258
335
  ```
259
336
 
260
- Register the public Git-backed marketplace:
337
+ Register the public Git-backed marketplace and install the plugin:
261
338
 
262
339
  ```bash
263
340
  codex plugin marketplace add memgraph/ai-toolkit --sparse .agents/plugins
341
+ codex plugin add context-graph@context-graph-plugins
264
342
  ```
265
343
 
266
- Then install or enable `context-graph` from the Codex plugin UI.
344
+ Both are non-interactive; `codex plugin add` installs and enables the plugin in one step (`codex plugin list --json` confirms `"enabled": true`).
267
345
 
268
346
  Check the installed hook environment with:
269
347
 
@@ -0,0 +1,3 @@
1
+ # Use Runtime Adapter terminology
2
+
3
+ Agent Context Graph supports agent development SDK integrations (OpenAI Agents SDK, Claude Agent SDK) and runtime hook integrations (Codex command hooks). We use **Runtime Adapter** as canonical term: covers both integration shapes. **SDK Adapter** wrongly implies every adapter attaches to an agent development SDK. Keeps Event Protocol independent of whether events came from in-process callbacks or command-hook payloads.
@@ -0,0 +1,7 @@
1
+ # Config file as the sole runtime source for hook subprocesses
2
+
3
+ Agent runtimes (Claude Code, Codex) spawn hook commands as non-interactive subprocesses — don't source shell profile files (`~/.zshrc`, `~/.bashrc`). Env vars set only there never reach hook processes. Instead of documenting fragile workarounds ("put exports in `~/.zshenv`"): hook subprocesses resolve config exclusively from a persistent file at `~/.config/context-graph/config.toml` (after CLI flags). Env vars not consulted at hook runtime — only a write-time convenience during `bootstrap`/`config set`, which persist values to the config file.
4
+
5
+ Avoids drift between what `doctor` sees (interactive shell, env vars present) and what hooks see (subprocess, env vars absent). One canonical way to configure hooks: the config file.
6
+
7
+ **Amended by** ADR 0003 (env var may select *which* config file is read, never what's in it) and ADR 0005 (config file also covers LLM API keys, resolved values passed as explicit `env=` to a further subprocess a hook spawns). Both preserve this ADR's core guarantee: config *values* still come only from the file.
@@ -0,0 +1,26 @@
1
+ # An environment variable may select the config file, never its contents
2
+
3
+ ADR 0002 made config file sole runtime source for hook subprocesses; env vars not consulted at hook runtime. Still true of config *values*. This ADR carves one exception: `CONTEXT_GRAPH_CONFIG` selects **which file** is read.
4
+
5
+ ## Why the exception is needed
6
+
7
+ Config path was single global (`~/.config/context-graph/config.toml`), no override. Hooks resolve everything from it -> pointing one Claude Code session at a different Memgraph meant rewriting that file, redirecting **every** session on the machine, not just the intended one.
8
+
9
+ Not hypothetical: found while building eval gold slice (drives real session against dedicated eval instance). With global config temporarily repointed, an unrelated Claude Code session's activity got recorded into the eval graph — exactly the ambient-session pollution that decision was meant to prevent. Mechanism defeated its own purpose.
10
+
11
+ No way to isolate a session short of changing `HOME` or running in a container.
12
+
13
+ ## Why it doesn't contradict ADR 0002
14
+
15
+ ADR 0002 was about **ambient** environment: hook subprocesses don't source shell profiles, so `~/.zshrc` values never reached them, and `doctor` (interactive, env present) disagreed with hooks (subprocess, env absent). That ADR removed config depending on where a process happened to launch from.
16
+
17
+ A config *path* handed down by the process spawning the session is the opposite: explicit, set by parent for its own child, drift-free — nothing ambient to drift from. `doctor` and the hooks it inspects agree by passing the same variable.
18
+
19
+ Distinction: **which file** vs **what's in it**. Values still come only from the file — ADR 0002's guarantee intact.
20
+
21
+ ## Consequences
22
+
23
+ - Callers needing an isolated session write their own config file, pass its path. `context_graph_eval.live.hooks_pointed_at` does this.
24
+ - Unset (normal case): behavior unchanged.
25
+ - `config set`/`bootstrap` write to the overridden path when set — makes a temporary config usable.
26
+ - `doctor` inspects whichever file the variable names — a session under an override diagnosable with same tool.
@@ -0,0 +1,3 @@
1
+ # Add user_id to SessionStartEvent
2
+
3
+ Event Protocol's `SessionStartEvent` carried no user identity. Memory Graph needs to own every `Memory` to a user node; Actions Graph + Skills Graph eventually need same. Instead of configuring user identity at `MemoryGraph` init time (couples identity to one component) or a caller-supplied resolver: add optional `user_id` field to `SessionStartEvent`. Keeps identity in shared event stream — all graph connectors access it, no breakage for existing callers that don't supply it.
@@ -0,0 +1,13 @@
1
+ # Config file also covers LLM API keys; explicit env for spawned subprocesses
2
+
3
+ ADR 0002 made `~/.config/context-graph/config.toml` sole runtime source for hook subprocess config: identity + Memgraph connection settings. Resolution happens as constructor kwargs passed directly to `SkillGraph`/`SessionsGraph`/`ActionsGraph` inside hook process — never written back to that process's `os.environ`.
4
+
5
+ `SessionsGraphConnector` (sessions-graph) spawns a **further** detached subprocess on `SESSION_END` when `auto_reconcile` enabled: `sessions-graph reconcile --session <id>`, LLM-backed entity extraction via LightRAG. Plain `subprocess.Popen(...)`, no explicit `env=` -> child only inherited whatever ambient `os.environ` parent hook process had — which, per ADR 0002, excludes resolved Memgraph config, and never had a path to an LLM API key at all (LightRAG's default `llm_model_func` reads `OPENAI_API_KEY` straight from `os.environ`, raises if unset).
6
+
7
+ Decided:
8
+
9
+ 1. Extend `HookConfig`/`config.toml` with `[llm]` section (`openai_api_key`, `anthropic_api_key`), resolved via `resolve_llm_env()`, mirroring `resolve_memgraph_env()`. `bootstrap` captures these from `OPENAI_API_KEY`/`ANTHROPIC_API_KEY` in env at write time, same as Memgraph credentials — env vars stay write-time convenience only, never consulted at hook runtime.
10
+ 2. Spawn site (`sessions_graph.connector._spawn_detached`, env from `_child_env`) builds **explicit `env=`** for child: copy of current `os.environ` overlaid with non-empty `resolve_memgraph_env()`/`resolve_llm_env()` values. Guarantees detached subprocess gets what hook process resolved, regardless of harness's own ambient environment.
11
+ 3. Defense in depth: `sessions-graph reconcile` (standalone via cron/manual, not only hook-spawned) also best-effort fills same config-file values via `os.environ.setdefault` at startup — consistent whether invoked by hook or by hand. Optional import of `agent_context_graph`, no-op if not installed (sessions-graph's `reconciliation` extra doesn't require it).
12
+
13
+ Same philosophy as ADR 0002 (config file canonical), closes the gap it missed: subprocesses spawned *by* a hook process, not just the hook process itself.
@@ -69,18 +69,29 @@ memgraph.password
69
69
  memgraph.database
70
70
  llm.openai_api_key
71
71
  llm.anthropic_api_key
72
+ reconcile.auto_reconcile
72
73
  ```
73
74
 
74
- The `llm.*` keys are only needed if you enable the `sessions-graph` connector
75
- with `auto_reconcile` (`SESSIONS_GRAPH_AUTO_RECONCILE=1` at connector
76
- construction time): reconciliation shells out to a detached
77
- `sessions-graph reconcile` subprocess that does LLM-backed entity extraction
78
- via LightRAG, and needs an `OPENAI_API_KEY` (or `ANTHROPIC_API_KEY`) the same
79
- way it needs Memgraph credentials — resolved from this config file and
80
- injected into that subprocess's environment explicitly, not inherited from
81
- ambient shell env (see ADR 0003). `agent-context-graph bootstrap` captures
75
+ The `llm.*` keys and `reconcile.auto_reconcile` are only needed if you enable
76
+ the `sessions-graph` connector's auto-trigger reconciliation
77
+ (`agent-context-graph config set reconcile.auto_reconcile true`):
78
+ reconciliation shells out to a detached `sessions-graph reconcile` subprocess
79
+ that does LLM-backed entity extraction via LightRAG, and needs an
80
+ `OPENAI_API_KEY` (or `ANTHROPIC_API_KEY`) the same way it needs Memgraph
81
+ credentials — resolved from this config file and injected into that
82
+ subprocess's environment explicitly, not inherited from ambient shell env
83
+ (see ADR 0005). `agent-context-graph bootstrap` captures
82
84
  `OPENAI_API_KEY`/`ANTHROPIC_API_KEY` from its own environment into the config
83
85
  file automatically, the same way it already does for `MEMGRAPH_*`.
86
+ `reconcile.auto_reconcile` is deliberately excluded from that automatic
87
+ capture — unlike those keys, nobody has it exported for an unrelated reason,
88
+ so it is only ever set via `config set reconcile.auto_reconcile true`.
89
+
90
+ `reconcile.auto_reconcile` itself is read directly by
91
+ `agent_context_graph.hooks.runner._add_sessions_graph_connector` on every hook
92
+ invocation (`resolve_auto_reconcile()`), not just at bootstrap/write time —
93
+ unlike the `llm.*`/`memgraph.*` keys, which are only ever overlaid into a
94
+ child subprocess's environment.
84
95
 
85
96
  To smoke test the generated command, copy the `"command"` value from `.codex/hooks.json` and run:
86
97
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "agent-context-graph"
3
- version = "0.2.0"
3
+ version = "0.3.1"
4
4
  description = "Connect agent SDKs to context-graph components (actions-graph, skills-graph, etc.)"
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -26,10 +26,14 @@ claude-code = "agent_context_graph.adapters.claude_code:PLUGIN"
26
26
  claude = [
27
27
  "claude-agent-sdk>=0.1.0",
28
28
  ]
29
+ mcp = [
30
+ "mcp>=1.23.0,<3",
31
+ ]
29
32
  openai = [
30
33
  "openai-agents>=0.1.0",
31
34
  ]
32
35
  test = [
36
+ "mcp>=1.23.0,<3",
33
37
  "pytest>=9.0.3",
34
38
  "pytest-asyncio>=0.24.0",
35
39
  ]
@@ -42,7 +42,7 @@ from .link import AgentLink
42
42
  from .protocols import GraphConnector, RuntimeAdapter
43
43
 
44
44
  try:
45
- __version__ = metadata.version(__package__)
45
+ __version__ = metadata.version(__package__ or __name__)
46
46
  except metadata.PackageNotFoundError:
47
47
  # Case where package metadata is not available.
48
48
  __version__ = ""