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.
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/.gitignore +3 -7
- agent_context_graph-0.3.1/CONTEXT.md +97 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/PKG-INFO +88 -7
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/README.md +84 -6
- agent_context_graph-0.3.1/docs/adr/0001-runtime-adapter-terminology.md +3 -0
- agent_context_graph-0.3.1/docs/adr/0002-config-file-only-hook-resolution.md +7 -0
- agent_context_graph-0.3.1/docs/adr/0003-config-path-override.md +26 -0
- agent_context_graph-0.3.1/docs/adr/0004-user-id-in-session-start-event.md +3 -0
- agent_context_graph-0.3.1/docs/adr/0005-config-file-covers-llm-key-and-subprocess-env.md +13 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/docs/command-hooks.md +19 -8
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/pyproject.toml +5 -1
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/__init__.py +1 -1
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/_identity.py +156 -32
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/claude.py +13 -9
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/claude_code.py +17 -1
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/codex.py +27 -4
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/cli.py +175 -15
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/runner.py +42 -9
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/runtime_plugin.py +13 -7
- agent_context_graph-0.3.1/src/agent_context_graph/mcp_server.py +89 -0
- agent_context_graph-0.3.1/src/agent_context_graph/tools.py +95 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_claude_code_adapter.py +58 -8
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_codex_adapter.py +46 -4
- agent_context_graph-0.3.1/tests/test_config_cli.py +92 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_hook_cli.py +36 -7
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_identity.py +100 -4
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_link.py +8 -3
- agent_context_graph-0.3.1/tests/test_runner_sessions_graph_connector.py +81 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/test_runtime_plugin.py +1 -1
- agent_context_graph-0.3.1/tests/test_tools.py +167 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/LICENSE +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/__init__.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/adapters/openai.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/events.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/__init__.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/hooks/cli.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/link.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/src/agent_context_graph/protocols.py +0 -0
- {agent_context_graph-0.2.0 → agent_context_graph-0.3.1}/tests/__init__.py +0 -0
- {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
|
-
|
|
194
|
-
|
|
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.
|
|
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>
|
|
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
|
-
|
|
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>
|
|
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
|
-
|
|
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
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
`sessions-graph reconcile` subprocess
|
|
78
|
-
via LightRAG, and needs an
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
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.
|
|
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__ = ""
|