agent-kg 0.7.0__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 (34) hide show
  1. agent_kg-0.7.0/LICENSE +94 -0
  2. agent_kg-0.7.0/PKG-INFO +377 -0
  3. agent_kg-0.7.0/README.md +312 -0
  4. agent_kg-0.7.0/pyproject.toml +211 -0
  5. agent_kg-0.7.0/src/agent_kg/__init__.py +70 -0
  6. agent_kg-0.7.0/src/agent_kg/app.py +543 -0
  7. agent_kg-0.7.0/src/agent_kg/assemble.py +132 -0
  8. agent_kg-0.7.0/src/agent_kg/cli/__init__.py +4 -0
  9. agent_kg-0.7.0/src/agent_kg/cli/main.py +1042 -0
  10. agent_kg-0.7.0/src/agent_kg/consolidate.py +93 -0
  11. agent_kg-0.7.0/src/agent_kg/graph.py +349 -0
  12. agent_kg-0.7.0/src/agent_kg/hooks/agent_kg_precompact_hook.sh +53 -0
  13. agent_kg-0.7.0/src/agent_kg/hooks/agent_kg_stop_hook.sh +97 -0
  14. agent_kg-0.7.0/src/agent_kg/hooks/agent_kg_user_prompt_hook.sh +39 -0
  15. agent_kg-0.7.0/src/agent_kg/index.py +135 -0
  16. agent_kg-0.7.0/src/agent_kg/ingest.py +361 -0
  17. agent_kg-0.7.0/src/agent_kg/kg.py +13 -0
  18. agent_kg-0.7.0/src/agent_kg/mcp/__init__.py +4 -0
  19. agent_kg-0.7.0/src/agent_kg/mcp/server.py +349 -0
  20. agent_kg-0.7.0/src/agent_kg/nlp/__init__.py +18 -0
  21. agent_kg-0.7.0/src/agent_kg/nlp/entities.py +190 -0
  22. agent_kg-0.7.0/src/agent_kg/nlp/intent.py +208 -0
  23. agent_kg-0.7.0/src/agent_kg/nlp/preferences.py +142 -0
  24. agent_kg-0.7.0/src/agent_kg/nlp/topics.py +152 -0
  25. agent_kg-0.7.0/src/agent_kg/onboard.py +259 -0
  26. agent_kg-0.7.0/src/agent_kg/prune.py +288 -0
  27. agent_kg-0.7.0/src/agent_kg/query.py +103 -0
  28. agent_kg-0.7.0/src/agent_kg/schema.py +247 -0
  29. agent_kg-0.7.0/src/agent_kg/session.py +108 -0
  30. agent_kg-0.7.0/src/agent_kg/snapshots.py +123 -0
  31. agent_kg-0.7.0/src/agent_kg/store.py +597 -0
  32. agent_kg-0.7.0/src/agent_kg/summarize.py +169 -0
  33. agent_kg-0.7.0/src/agent_kg/user_profile.py +493 -0
  34. agent_kg-0.7.0/src/agent_kg/viz.py +413 -0
agent_kg-0.7.0/LICENSE ADDED
@@ -0,0 +1,94 @@
1
+ Elastic License 2.0
2
+
3
+ URL: https://www.elastic.co/licensing/elastic-license
4
+
5
+ ## Acceptance
6
+
7
+ By using the software, you agree to all of the terms and conditions below.
8
+
9
+ ## Copyright License
10
+
11
+ The licensor grants you a non-exclusive, royalty-free, worldwide,
12
+ non-sublicensable, non-transferable license to use, copy, distribute, make
13
+ available, and prepare derivative works of the software, in each case subject to
14
+ the limitations and conditions below.
15
+
16
+ ## Limitations
17
+
18
+ **You may not provide the software to third parties as a hosted or managed
19
+ service, where the service provides users with access to any substantial set of
20
+ the features or functionality of the software.**
21
+
22
+ You may not move, change, disable, or circumvent the license key functionality
23
+ in the software, and you may not remove or obscure any functionality in the
24
+ software that is protected by the license key.
25
+
26
+ You may not alter, remove, or obscure any licensing, copyright, or other notices
27
+ of the licensor in the software. Any use of the licensor's trademarks is subject
28
+ to applicable law.
29
+
30
+ ## Patents
31
+
32
+ The licensor grants you a license, under any patent claims the licensor can
33
+ license, or becomes able to license, to make, have made, use, sell, offer for
34
+ sale, import and have imported the software, in each case subject to the
35
+ limitations and conditions in this license. This license does not cover any
36
+ patent claims that you cause to be infringed by modifications or additions to the
37
+ software. If you or your company make any written claim that the software
38
+ infringes or contributes to infringement of any patent, your patent license for
39
+ the software granted under these terms ends immediately. If your company makes
40
+ such a claim, your patent license ends immediately for work on behalf of your
41
+ company.
42
+
43
+ ## Notices
44
+
45
+ You must ensure that anyone who gets a copy of any part of the software from you
46
+ also gets a copy of these terms or the URL for them above, as well as copies of
47
+ any plain-text lines beginning with "Required Notice:" that the licensor provided
48
+ with the software. For example:
49
+
50
+ Required Notice: Copyright (c) 2026 Eric G. Suchanek, PhD
51
+
52
+ ## No Other Rights
53
+
54
+ These terms do not imply any other licenses not expressly granted in this
55
+ license.
56
+
57
+ ## Termination
58
+
59
+ If you use the software in violation of these terms, such use is not licensed,
60
+ and your licenses will automatically terminate. If the licensor provides you with
61
+ a notice of your violation, and you cease all violation of this license no later
62
+ than 30 days after you receive that notice, your licenses will be reinstated
63
+ retroactively. However, if you violate these terms after such reinstatement, any
64
+ additional violation of these terms will cause your licenses to terminate
65
+ automatically and permanently.
66
+
67
+ ## No Liability
68
+
69
+ *As far as the law allows, the software comes as is, without any warranty or
70
+ condition, and the licensor will not be liable to you for any damages arising out
71
+ of these terms or the use or nature of the software, under any kind of legal
72
+ claim.*
73
+
74
+ ## Definitions
75
+
76
+ The **licensor** is the entity offering these terms, and the **software** is the
77
+ software the licensor makes available under these terms, including any portion of
78
+ it.
79
+
80
+ **You** refers to the individual or entity agreeing to these terms.
81
+
82
+ **Your company** is any legal entity, sole proprietorship, or other kind of
83
+ organization that you work for, plus all organizations that have control over,
84
+ are under the control of, or are under common control with that organization.
85
+ Control means ownership of substantially all the assets of an entity, or the
86
+ power to direct its management and policies by vote, contract, or otherwise.
87
+ Control can be direct or indirect.
88
+
89
+ **Your licenses** are all the licenses granted to you for the software under
90
+ these terms.
91
+
92
+ **Use** means anything you do with the software requiring one of your licenses.
93
+
94
+ **Trademark** means trademarks, service marks, and similar rights.
@@ -0,0 +1,377 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-kg
3
+ Version: 0.7.0
4
+ Summary: Conversational memory as a knowledge graph
5
+ License-Expression: Elastic-2.0
6
+ License-File: LICENSE
7
+ Keywords: knowledge-graph,conversation-memory,lancedb,mcp,semantic-search,claude
8
+ Author: Eric G. Suchanek, PhD
9
+ Author-email: suchanek@flux-frontiers.com
10
+ Requires-Python: >=3.12,<3.14
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Provides-Extra: all
19
+ Provides-Extra: dev
20
+ Provides-Extra: kgdeps
21
+ Provides-Extra: llm
22
+ Provides-Extra: local
23
+ Provides-Extra: viz
24
+ Requires-Dist: anthropic (>=0.25.0) ; extra == "all"
25
+ Requires-Dist: anthropic (>=0.25.0) ; extra == "llm"
26
+ Requires-Dist: click (>=8.1.0,<9)
27
+ Requires-Dist: detect-secrets (>=1.5.0) ; extra == "all"
28
+ Requires-Dist: detect-secrets (>=1.5.0) ; extra == "dev"
29
+ Requires-Dist: doc-kg (>=0.16.0) ; extra == "all"
30
+ Requires-Dist: doc-kg (>=0.16.0) ; extra == "kgdeps"
31
+ Requires-Dist: kgmodule-utils (>=0.4.5)
32
+ Requires-Dist: lancedb (>=0.29.0)
33
+ Requires-Dist: mcp (>=1.0.0)
34
+ Requires-Dist: numpy (>=1.24.0)
35
+ Requires-Dist: openai (>=1.30.0) ; extra == "all"
36
+ Requires-Dist: openai (>=1.30.0) ; extra == "local"
37
+ Requires-Dist: pdoc (>=14.0.0) ; extra == "all"
38
+ Requires-Dist: pdoc (>=14.0.0) ; extra == "dev"
39
+ Requires-Dist: pre-commit (>=4.5.1) ; extra == "all"
40
+ Requires-Dist: pre-commit (>=4.5.1) ; extra == "dev"
41
+ Requires-Dist: pycode-kg (>=0.19.3) ; extra == "all"
42
+ Requires-Dist: pycode-kg (>=0.19.3) ; extra == "kgdeps"
43
+ Requires-Dist: pytest (>=8.0.0) ; extra == "all"
44
+ Requires-Dist: pytest (>=8.0.0) ; extra == "dev"
45
+ Requires-Dist: pytest-cov (>=5.0.0) ; extra == "all"
46
+ Requires-Dist: pytest-cov (>=5.0.0) ; extra == "dev"
47
+ Requires-Dist: pyvis (>=0.3.2) ; extra == "all"
48
+ Requires-Dist: pyvis (>=0.3.2) ; extra == "viz"
49
+ Requires-Dist: rich (>=14.0.0)
50
+ Requires-Dist: ruff (>=0.4.0) ; extra == "all"
51
+ Requires-Dist: ruff (>=0.4.0) ; extra == "dev"
52
+ Requires-Dist: safetensors (>=0.5.0)
53
+ Requires-Dist: sentence-transformers (>=5.2.0)
54
+ Requires-Dist: spacy (>=3.7.0)
55
+ Requires-Dist: streamlit (>=1.35.0) ; extra == "all"
56
+ Requires-Dist: streamlit (>=1.35.0) ; extra == "viz"
57
+ Requires-Dist: torch (>=2.5.1)
58
+ Requires-Dist: transformers (>=4.40.0,<4.57)
59
+ Requires-Dist: ty (>=0.0.41) ; extra == "all"
60
+ Requires-Dist: ty (>=0.0.41) ; extra == "dev"
61
+ Project-URL: Homepage, https://github.com/Flux-Frontiers/agent_kg
62
+ Project-URL: Repository, https://github.com/Flux-Frontiers/agent_kg
63
+ Description-Content-Type: text/markdown
64
+
65
+
66
+ [![Python](https://img.shields.io/badge/python-3.12%20%7C%203.13-blue.svg)](https://www.python.org/)
67
+ [![License: Elastic-2.0](https://img.shields.io/badge/License-Elastic%202.0-blue.svg)](https://www.elastic.co/licensing/elastic-license)
68
+ [![Version](https://img.shields.io/badge/version-0.7.0-blue.svg)](https://github.com/Flux-Frontiers/agent_kg/releases)
69
+ [![Poetry](https://img.shields.io/endpoint?url=https://python-poetry.org/badge/v0.json)](https://python-poetry.org/)
70
+ [![DOI](https://zenodo.org/badge/1186774406.svg)](https://zenodo.org/badge/latestdoi/1186774406)
71
+
72
+ **AgentKG** — Conversational Memory as a Live, Queryable Knowledge Graph
73
+
74
+ *Author: Eric G. Suchanek, PhD*
75
+
76
+ *Flux-Frontiers, Liberty TWP, OH*
77
+
78
+ ---
79
+
80
+ ## Overview
81
+
82
+ AgentKG stores every conversation turn, topic, entity, intent, task, and user preference as a node in a **persistent knowledge graph** (SQLite + LanceDB). Edges encode relationships between turns, sessions, and profile facts. The result is a queryable, prunable, semantically searchable memory that survives context resets and accumulates across projects.
83
+
84
+ The graph is split into two stores:
85
+
86
+ - **Per-repo conversation graph** (`.agentkg/`) — turns, topics, entities, intents, tasks, summaries
87
+ - **Global user profile** (`~/.kgrag/profiles/<person>/`) — preferences, expertise, style, commitments, interests; never pruned
88
+
89
+ Embeddings use `all-MiniLM-L6-v2` (384-dim) via `sentence-transformers` + LanceDB. Structure is treated as ground truth; semantic search is strictly a retrieval accelerant.
90
+
91
+ ---
92
+
93
+ ## Features
94
+
95
+ - **Incremental ingest** — every turn indexed in real-time; topics, entities, and intents extracted automatically via spaCy + keyword fallback
96
+ - **Hybrid query** — semantic seeding (LanceDB) + structural expansion (graph traversal)
97
+ - **Global UserProfile tree** — preference, expertise, style, commitment, interest, and context nodes accumulated across all repos
98
+ - **Structured onboarding** — four-phase interview populates the profile on first use
99
+ - **Implicit profile updates** — NLP pipeline extracts standing rules from natural language ("always do X", "I prefer Y")
100
+ - **Context assembly** — token-budgeted context block built from the graph for LLM prompt injection
101
+ - **KG Context Pruning** — old turns compressed into Summary nodes when the graph grows large
102
+ - **Temporal snapshots** — point-in-time JSON snapshots for diffing session state
103
+ - **MCP server** — exposes the full query pipeline as structured tools for AI agent integration
104
+ - **Script-based hooks** — three Claude Code hooks (UserPromptSubmit, Stop, PreCompact) deployed as shell scripts via `install-hooks`
105
+
106
+ ---
107
+
108
+ ## Quick Start
109
+
110
+ ```bash
111
+ # 1. Download the embedding model and create your profile directory
112
+ agentkg init --person <you>
113
+
114
+ # 2. Run the onboarding interview
115
+ agentkg onboard --person <you>
116
+
117
+ # 3. Check your profile
118
+ agentkg profile --person <you>
119
+ ```
120
+
121
+ Embeddings are on by default. `init` pre-warms the model cache so the first `ingest` does not pause to download.
122
+
123
+ ---
124
+
125
+ ## Person ID
126
+
127
+ `--person` identifies the **global user profile** at `~/.kgrag/profiles/<person>/`.
128
+ The default is your OS login name (`getpass.getuser()`), which is correct automatically
129
+ on a single-user machine — you rarely need to set it explicitly.
130
+
131
+ **`--person` only affects profile-scoped commands:** `init`, `onboard`, `profile`,
132
+ `viz --profile`, `wipe --global`. Local graph commands (`query`, `assemble`, `stats`,
133
+ `sessions`, `snapshot`, `prune`, `ingest`, `analyze`) are repo-scoped and ignore it.
134
+
135
+ ```bash
136
+ # Single-user machine: default is correct, no flag needed
137
+ agentkg onboard # writes to ~/.kgrag/profiles/<your-os-username>/
138
+ agentkg profile # reads the same path ← correct
139
+
140
+ # Multi-user or named profiles: be explicit on profile commands only
141
+ agentkg onboard --person alice
142
+ agentkg profile --person alice
143
+ agentkg query "auth strategy" # no --person needed here
144
+ ```
145
+
146
+ If `agentkg profile` returns an empty `# UserProfile`, check which `--person` value
147
+ was used during `onboard`. The completion message prints the exact path.
148
+
149
+ ---
150
+
151
+ ## CLI Reference
152
+
153
+ All commands accept `--repo <path>` (default `.`). `--person <id>` defaults to your OS
154
+ username and is only needed for profile-scoped commands (`init`, `onboard`, `profile`,
155
+ `viz --profile`, `wipe --global`).
156
+
157
+ | Command | Description |
158
+ |---|---|
159
+ | `agentkg init` | Download embedding model and create profile directory (run first) |
160
+ | `agentkg install-hooks` | Deploy hook scripts and wire Claude Code settings.json |
161
+ | `agentkg onboard` | Run the structured UserProfile onboarding interview |
162
+ | `agentkg profile` | Show the UserProfile as Markdown |
163
+ | `agentkg ingest` | Add a turn to the conversation graph |
164
+ | `agentkg query` | Semantic search over the graph |
165
+ | `agentkg assemble` | Assemble a token-budgeted context block |
166
+ | `agentkg prune` | Compress old turns into Summary nodes |
167
+ | `agentkg stats` | Show graph node/edge counts |
168
+ | `agentkg analyze` | Print a full Markdown analysis report |
169
+ | `agentkg sessions` | List all sessions for this repo |
170
+ | `agentkg snapshot` | Capture a point-in-time snapshot |
171
+ | `agentkg mcp` | Start the MCP server (stdio transport) |
172
+
173
+ Each command also ships as a dedicated `agentkg-<name>` script — no `poetry run` needed:
174
+
175
+ ```bash
176
+ agentkg-init --person egs # profile-scoped
177
+ agentkg-onboard --person egs # profile-scoped
178
+ agentkg-profile --person egs # profile-scoped
179
+ agentkg-stats --repo .
180
+ agentkg-query "authentication strategy" --k 8 --repo .
181
+ agentkg-assemble "what did we decide about auth?" --budget 4000 --repo .
182
+ agentkg-prune --window 20 --repo .
183
+ agentkg-mcp
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Installation
189
+
190
+ **Requirements:** Python ≥ 3.12, < 3.14
191
+
192
+ ### Poetry (recommended)
193
+
194
+ ```bash
195
+ git clone https://github.com/Flux-Frontiers/agent_kg.git
196
+ cd agent_kg
197
+ poetry install
198
+ ```
199
+
200
+ ### As a dependency
201
+
202
+ ```toml
203
+ [tool.poetry.dependencies]
204
+ agent-kg = {git = "https://github.com/Flux-Frontiers/agent_kg.git"}
205
+ ```
206
+
207
+ ### Optional extras
208
+
209
+ ```bash
210
+ poetry install -E llm # Anthropic summarizer backend
211
+ poetry install -E viz # Streamlit explorer UI + pyvis graph visualization
212
+ poetry install -E local # httpx for local LLM backends
213
+ poetry install -E all # everything above
214
+ ```
215
+
216
+ spaCy is a **required** dependency (not an extra) — it is always installed and drives topic and entity extraction. The `en_core_web_sm` model must be downloaded separately:
217
+
218
+ ```bash
219
+ python -m spacy download en_core_web_sm
220
+ ```
221
+
222
+ Without the model, extraction falls back to keyword/regex heuristics automatically.
223
+
224
+ ---
225
+
226
+ ## Data Layout
227
+
228
+ ```
229
+ <repo-root>/.agentkg/
230
+ graph.sqlite # nodes + edges (conversation graph)
231
+ lancedb/ # vector embeddings
232
+ snapshots/ # point-in-time JSON snapshots
233
+
234
+ ~/.kgrag/profiles/<person>/
235
+ userprofile.sqlite # global UserProfile tree (never pruned)
236
+ ```
237
+
238
+ ---
239
+
240
+ ## Node Kinds
241
+
242
+ | Kind | What it stores |
243
+ |---|---|
244
+ | `turn` | Raw user/assistant message text |
245
+ | `topic` | N-gram topics extracted from turns |
246
+ | `entity` | Named entities (people, tools, projects) |
247
+ | `intent` | Classified intent category per turn |
248
+ | `task` | Action items extracted from conversation |
249
+ | `summary` | Pruned turn summaries (after prune pass) |
250
+ | `preference` | User coding/style preferences (profile) |
251
+ | `commitment` | Standing rules — "always do X" (profile) |
252
+ | `expertise` | Domain knowledge areas (profile) |
253
+ | `interest` | Topics the user cares about (profile) |
254
+ | `style` | Formatting/docstring/verbosity preferences (profile) |
255
+ | `context` | Role, machine, projects context (profile) |
256
+ | `education` | Educational background entries (profile) |
257
+
258
+ ---
259
+
260
+ ## MCP Server
261
+
262
+ AgentKG ships a **Model Context Protocol (MCP) server** that exposes the full query pipeline as structured tools for AI agents.
263
+
264
+ ```bash
265
+ agentkg-mcp # stdio transport
266
+ ```
267
+
268
+ Configure in `.mcp.json` (Claude Code / Kilo Code):
269
+
270
+ ```json
271
+ {
272
+ "mcpServers": {
273
+ "agent-kg": {
274
+ "command": "agentkg-mcp"
275
+ }
276
+ }
277
+ }
278
+ ```
279
+
280
+ ---
281
+
282
+ ## Hooks (Auto-Ingest)
283
+
284
+ AgentKG ships three Claude Code hook scripts that are deployed by the installer:
285
+
286
+ | Hook | Script | What it does |
287
+ |---|---|---|
288
+ | `UserPromptSubmit` | `agent_kg_user_prompt_hook.sh` | Ingests each user turn with embeddings |
289
+ | `Stop` | `agent_kg_stop_hook.sh` | Ingests assistant turn; runs `prune` async every 20 exchanges; snapshots |
290
+ | `PreCompact` | `agent_kg_precompact_hook.sh` | Runs `prune` + snapshot **synchronously** before context compaction — ensures no turns are lost |
291
+
292
+ ### Install
293
+
294
+ ```bash
295
+ # Deploy scripts to ~/.agentkg/hooks/ and wire into ~/.claude/settings.json (all repos)
296
+ agentkg install-hooks --global
297
+
298
+ # Or wire into .claude/settings.json for this repo only
299
+ agentkg install-hooks --claude
300
+
301
+ # Force-overwrite existing hooks
302
+ agentkg install-hooks --global --force
303
+ ```
304
+
305
+ The installer:
306
+ 1. Copies the three `.sh` scripts from the package into `~/.agentkg/hooks/` (executable)
307
+ 2. Merges `UserPromptSubmit`, `Stop`, and `PreCompact` entries into the target `settings.json`
308
+
309
+ The scripts are portable — they use `git rev-parse --show-toplevel` to locate the repo and only fire when a `.agentkg/` directory is present.
310
+
311
+ ### Hook state and logs
312
+
313
+ ```
314
+ ~/.agentkg/hook_state/
315
+ hook.log # timestamped log of all hook activity
316
+ <session_id>_last_consolidate # exchange counter for periodic prune
317
+ ```
318
+
319
+ ---
320
+
321
+ ## Project Structure
322
+
323
+ ```
324
+ agent_kg/
325
+ ├── README.md
326
+ ├── pyproject.toml
327
+ ├── hooks/ # reference copies of hook scripts
328
+ │ ├── agent_kg_user_prompt_hook.sh
329
+ │ ├── agent_kg_stop_hook.sh
330
+ │ └── agent_kg_precompact_hook.sh
331
+ ├── scripts/
332
+ │ └── generate_wiki.py # GitHub wiki generator
333
+ ├── src/
334
+ │ └── agent_kg/
335
+ │ ├── __init__.py
336
+ │ ├── graph.py # AgentKG orchestrator
337
+ │ ├── store.py # SQLite + LanceDB storage
338
+ │ ├── index.py # LanceDB semantic indexing
339
+ │ ├── ingest.py # Phase 1 incremental turn ingest
340
+ │ ├── user_profile.py # Global UserProfile tree
341
+ │ ├── onboard.py # Structured onboarding interview
342
+ │ ├── session.py # Session lifecycle
343
+ │ ├── query.py # Hybrid semantic + graph query
344
+ │ ├── assemble.py # Token-budgeted context assembly
345
+ │ ├── prune.py # KG Context Pruning
346
+ │ ├── consolidate.py # Deferred embedding consolidation
347
+ │ ├── summarize.py # LLM-backed summarization
348
+ │ ├── snapshots.py # Point-in-time snapshot capture
349
+ │ ├── schema.py # Node/Edge dataclasses
350
+ │ ├── kg.py # High-level KG facade
351
+ │ ├── app.py # Streamlit explorer UI
352
+ │ ├── viz.py # Visualization helpers (Rich + pyvis)
353
+ │ ├── hooks/ # bundled hook scripts (deployed by install-hooks)
354
+ │ │ ├── agent_kg_user_prompt_hook.sh
355
+ │ │ ├── agent_kg_stop_hook.sh
356
+ │ │ └── agent_kg_precompact_hook.sh
357
+ │ ├── cli/
358
+ │ │ ├── main.py # Click CLI entry points
359
+ │ │ └── __init__.py
360
+ │ ├── mcp/
361
+ │ │ └── server.py # MCP server
362
+ │ └── nlp/ # NLP pipeline (spaCy + regex fallback)
363
+ │ ├── entities.py
364
+ │ ├── intent.py
365
+ │ ├── preferences.py
366
+ │ └── topics.py
367
+ └── tests/
368
+ ```
369
+
370
+ ---
371
+
372
+ ## License
373
+
374
+ [Elastic License 2.0](https://www.elastic.co/licensing/elastic-license) — see [LICENSE](LICENSE).
375
+
376
+ Free to use, modify, and distribute. You may not offer the software as a hosted or managed service to third parties. Commercial use internally is permitted.
377
+