abbacus-cortex 0.2.1__tar.gz → 0.2.2__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.
- abbacus_cortex-0.2.2/LICENSE +69 -0
- abbacus_cortex-0.2.1/README.md → abbacus_cortex-0.2.2/PKG-INFO +66 -1
- abbacus_cortex-0.2.1/PKG-INFO → abbacus_cortex-0.2.2/README.md +26 -24
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/pyproject.toml +28 -3
- abbacus_cortex-0.2.2/src/cortex/.DS_Store +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/__init__.py +1 -1
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/cli/backup.py +9 -7
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/cli/install.py +15 -11
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/cli/main.py +25 -51
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/core/constants.py +32 -26
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/core/errors.py +5 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/core/logging.py +6 -4
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/static/js/graph.js +26 -17
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/db/content_store.py +31 -21
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/db/graph_store.py +43 -37
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/db/store.py +5 -4
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/advanced_reason.py +17 -22
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/enrich.py +1 -3
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/importer.py +56 -32
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/link.py +12 -10
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/normalize.py +3 -1
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/orchestrator.py +3 -1
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/reason.py +11 -12
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/templates.py +8 -3
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/temporal.py +1 -3
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/retrieval/engine.py +12 -27
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/retrieval/graph.py +42 -39
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/retrieval/learner.py +4 -9
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/retrieval/presenters.py +66 -79
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/services/embeddings.py +1 -3
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/services/llm.py +86 -7
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/api/server.py +16 -46
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/mcp/client.py +6 -18
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/mcp/server.py +33 -21
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/__main__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/cli/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/core/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/core/config.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/server.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/static/css/style.css +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/base.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/create.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/detail.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/documents.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/entities.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/error.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/graph.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/home.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/login.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/settings.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/dashboard/templates/trail.html +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/db/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/ontology/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/ontology/cortex.ttl +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/ontology/namespaces.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/ontology/resolver.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/pipeline/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/py.typed +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/retrieval/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/services/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/tools/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/api/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/mcp/__init__.py +0 -0
- {abbacus_cortex-0.2.1 → abbacus_cortex-0.2.2}/src/cortex/transport/mcp/__main__.py +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: Abbacus Group
|
|
6
|
+
|
|
7
|
+
Licensed Work: Cortex v0.2.1
|
|
8
|
+
The Licensed Work is the Cortex software, available at
|
|
9
|
+
https://github.com/abbacusgroup/Cortex
|
|
10
|
+
|
|
11
|
+
Additional Use Grant: You may use the Licensed Work for your internal
|
|
12
|
+
business purposes.
|
|
13
|
+
|
|
14
|
+
Change Date: 2030-04-11
|
|
15
|
+
|
|
16
|
+
Change License: MIT License
|
|
17
|
+
|
|
18
|
+
For information about alternative licensing arrangements for the Licensed Work,
|
|
19
|
+
please contact the Licensor.
|
|
20
|
+
|
|
21
|
+
Notice
|
|
22
|
+
|
|
23
|
+
Business Source License 1.1
|
|
24
|
+
|
|
25
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
26
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
27
|
+
|
|
28
|
+
-----------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
Terms
|
|
31
|
+
|
|
32
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
33
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
34
|
+
Licensor may make an Additional Use Grant, above, permitting limited production
|
|
35
|
+
use.
|
|
36
|
+
|
|
37
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
38
|
+
available distribution of a specific version of the Licensed Work under this
|
|
39
|
+
License, whichever comes first, the Licensor hereby grants you rights under the
|
|
40
|
+
terms of the Change License, and the rights granted in the paragraph above
|
|
41
|
+
terminate.
|
|
42
|
+
|
|
43
|
+
If your use of the Licensed Work does not comply with the requirements currently
|
|
44
|
+
in effect as described in this License, you must purchase a commercial license
|
|
45
|
+
from the Licensor, its affiliated entities, or authorized resellers, or you must
|
|
46
|
+
refrain from using the Licensed Work.
|
|
47
|
+
|
|
48
|
+
All copies of the original and modified Licensed Work, and derivative works of
|
|
49
|
+
the Licensed Work, are subject to this License. This License applies separately
|
|
50
|
+
for each version of the Licensed Work and the Change Date may vary for each
|
|
51
|
+
version of the Licensed Work released by Licensor.
|
|
52
|
+
|
|
53
|
+
You must conspicuously display this License on each original or modified copy of
|
|
54
|
+
the Licensed Work. If you receive the Licensed Work in original or modified form
|
|
55
|
+
from a third party, the terms and conditions set forth in this License apply to
|
|
56
|
+
your use of that work.
|
|
57
|
+
|
|
58
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
59
|
+
terminate your rights under this License for the current and all other versions
|
|
60
|
+
of the Licensed Work.
|
|
61
|
+
|
|
62
|
+
This License does not grant you any right in any trademark or logo of Licensor
|
|
63
|
+
or its affiliates (provided that you may use a trademark or logo of Licensor as
|
|
64
|
+
expressly required by this License).
|
|
65
|
+
|
|
66
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
67
|
+
"AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS
|
|
68
|
+
OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF MERCHANTABILITY,
|
|
69
|
+
FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND TITLE.
|
|
@@ -1,9 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: abbacus-cortex
|
|
3
|
+
Version: 0.2.2
|
|
4
|
+
Summary: Cognitive knowledge system with formal ontology, reasoning, and intelligence serving
|
|
5
|
+
Keywords: knowledge-graph,knowledge-management,mcp,reasoning,ontology,rdf,ai,semantic-search,llm
|
|
6
|
+
Author: Fabrizzio Silveira
|
|
7
|
+
Author-email: Fabrizzio Silveira <74255714+grayisnotacolor@users.noreply.github.com>
|
|
8
|
+
License-Expression: BUSL-1.1
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: Other/Proprietary License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Classifier: Topic :: Database :: Database Engines/Servers
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Dist: pyoxigraph>=0.4
|
|
21
|
+
Requires-Dist: aiosqlite>=0.20
|
|
22
|
+
Requires-Dist: fastapi>=0.115
|
|
23
|
+
Requires-Dist: uvicorn[standard]>=0.34
|
|
24
|
+
Requires-Dist: typer>=0.15
|
|
25
|
+
Requires-Dist: jinja2>=3.1
|
|
26
|
+
Requires-Dist: python-dotenv>=1.1
|
|
27
|
+
Requires-Dist: bcrypt>=4.2
|
|
28
|
+
Requires-Dist: mcp>=1.6
|
|
29
|
+
Requires-Dist: httpx>=0.28
|
|
30
|
+
Requires-Dist: litellm>=1.60
|
|
31
|
+
Requires-Dist: sentence-transformers>=3.4 ; extra == 'embeddings'
|
|
32
|
+
Requires-Python: >=3.12
|
|
33
|
+
Project-URL: Homepage, https://github.com/abbacusgroup/Cortex
|
|
34
|
+
Project-URL: Repository, https://github.com/abbacusgroup/Cortex
|
|
35
|
+
Project-URL: Documentation, https://github.com/abbacusgroup/Cortex#readme
|
|
36
|
+
Project-URL: Changelog, https://github.com/abbacusgroup/Cortex/blob/main/CHANGELOG.md
|
|
37
|
+
Project-URL: Bug Tracker, https://github.com/abbacusgroup/Cortex/issues
|
|
38
|
+
Provides-Extra: embeddings
|
|
39
|
+
Description-Content-Type: text/markdown
|
|
40
|
+
|
|
1
41
|
# Cortex
|
|
2
42
|
|
|
43
|
+
<!-- mcp-name: io.github.abbacusgroup/cortex -->
|
|
44
|
+
|
|
45
|
+
[](https://github.com/abbacusgroup/Cortex/actions/workflows/test.yml)
|
|
46
|
+
[](https://pypi.org/project/abbacus-cortex/)
|
|
47
|
+
[](https://pypi.org/project/abbacus-cortex/)
|
|
48
|
+
[](LICENSE)
|
|
49
|
+
|
|
3
50
|
Cognitive knowledge system with formal ontology, reasoning, and intelligence serving.
|
|
4
51
|
|
|
5
52
|
Cortex captures knowledge objects (decisions, lessons, fixes, sessions, research, ideas), classifies them with an OWL-RL ontology, discovers relationships, reasons over the graph, and serves intelligence through hybrid retrieval.
|
|
6
53
|
|
|
54
|
+

|
|
55
|
+
|
|
56
|
+

|
|
57
|
+
|
|
7
58
|
## Install
|
|
8
59
|
|
|
9
60
|
```bash
|
|
@@ -187,6 +238,20 @@ decision, lesson, fix, session, research, source, synthesis, idea
|
|
|
187
238
|
|
|
188
239
|
causedBy, contradicts (symmetric), supports, supersedes (transitive), dependsOn, ledTo (inverse of causedBy), implements, mentions
|
|
189
240
|
|
|
241
|
+
## Privacy
|
|
242
|
+
|
|
243
|
+
Cortex stores all data locally. No telemetry, no analytics, no phone-home. If you configure an LLM provider (via `CORTEX_LLM_API_KEY`), object content may be sent to that provider for classification and reasoning. Embeddings are computed locally by default using `sentence-transformers`.
|
|
244
|
+
|
|
190
245
|
## License
|
|
191
246
|
|
|
192
|
-
Copyright Abbacus Group.
|
|
247
|
+
Copyright (c) 2026 Abbacus Group. Licensed under the [Business Source License 1.1](LICENSE).
|
|
248
|
+
|
|
249
|
+
- **Additional Use Grant:** You may use the Licensed Work for your internal business purposes.
|
|
250
|
+
- **Change Date:** 2030-04-11
|
|
251
|
+
- **Change License:** MIT
|
|
252
|
+
|
|
253
|
+
After the Change Date, this software converts to the MIT license.
|
|
254
|
+
|
|
255
|
+
## Trademark Notice
|
|
256
|
+
|
|
257
|
+
Cortex is a project of Abbacus Group and is not affiliated with any other product named Cortex.
|
|
@@ -1,32 +1,20 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: abbacus-cortex
|
|
3
|
-
Version: 0.2.1
|
|
4
|
-
Summary: Cognitive knowledge system with formal ontology, reasoning, and intelligence serving
|
|
5
|
-
Author: Fabrizzio Silveira
|
|
6
|
-
Author-email: Fabrizzio Silveira <74255714+grayisnotacolor@users.noreply.github.com>
|
|
7
|
-
Requires-Dist: pyoxigraph>=0.4
|
|
8
|
-
Requires-Dist: aiosqlite>=0.20
|
|
9
|
-
Requires-Dist: fastapi>=0.115
|
|
10
|
-
Requires-Dist: uvicorn[standard]>=0.34
|
|
11
|
-
Requires-Dist: typer>=0.15
|
|
12
|
-
Requires-Dist: jinja2>=3.1
|
|
13
|
-
Requires-Dist: python-dotenv>=1.1
|
|
14
|
-
Requires-Dist: bcrypt>=4.2
|
|
15
|
-
Requires-Dist: mcp>=1.6
|
|
16
|
-
Requires-Dist: httpx>=0.28
|
|
17
|
-
Requires-Dist: sentence-transformers>=3.4 ; extra == 'embeddings'
|
|
18
|
-
Requires-Dist: litellm>=1.60 ; extra == 'llm'
|
|
19
|
-
Requires-Python: >=3.12
|
|
20
|
-
Provides-Extra: embeddings
|
|
21
|
-
Provides-Extra: llm
|
|
22
|
-
Description-Content-Type: text/markdown
|
|
23
|
-
|
|
24
1
|
# Cortex
|
|
25
2
|
|
|
3
|
+
<!-- mcp-name: io.github.abbacusgroup/cortex -->
|
|
4
|
+
|
|
5
|
+
[](https://github.com/abbacusgroup/Cortex/actions/workflows/test.yml)
|
|
6
|
+
[](https://pypi.org/project/abbacus-cortex/)
|
|
7
|
+
[](https://pypi.org/project/abbacus-cortex/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
|
|
26
10
|
Cognitive knowledge system with formal ontology, reasoning, and intelligence serving.
|
|
27
11
|
|
|
28
12
|
Cortex captures knowledge objects (decisions, lessons, fixes, sessions, research, ideas), classifies them with an OWL-RL ontology, discovers relationships, reasons over the graph, and serves intelligence through hybrid retrieval.
|
|
29
13
|
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+

|
|
17
|
+
|
|
30
18
|
## Install
|
|
31
19
|
|
|
32
20
|
```bash
|
|
@@ -210,6 +198,20 @@ decision, lesson, fix, session, research, source, synthesis, idea
|
|
|
210
198
|
|
|
211
199
|
causedBy, contradicts (symmetric), supports, supersedes (transitive), dependsOn, ledTo (inverse of causedBy), implements, mentions
|
|
212
200
|
|
|
201
|
+
## Privacy
|
|
202
|
+
|
|
203
|
+
Cortex stores all data locally. No telemetry, no analytics, no phone-home. If you configure an LLM provider (via `CORTEX_LLM_API_KEY`), object content may be sent to that provider for classification and reasoning. Embeddings are computed locally by default using `sentence-transformers`.
|
|
204
|
+
|
|
213
205
|
## License
|
|
214
206
|
|
|
215
|
-
Copyright Abbacus Group.
|
|
207
|
+
Copyright (c) 2026 Abbacus Group. Licensed under the [Business Source License 1.1](LICENSE).
|
|
208
|
+
|
|
209
|
+
- **Additional Use Grant:** You may use the Licensed Work for your internal business purposes.
|
|
210
|
+
- **Change Date:** 2030-04-11
|
|
211
|
+
- **Change License:** MIT
|
|
212
|
+
|
|
213
|
+
After the Change Date, this software converts to the MIT license.
|
|
214
|
+
|
|
215
|
+
## Trademark Notice
|
|
216
|
+
|
|
217
|
+
Cortex is a project of Abbacus Group and is not affiliated with any other product named Cortex.
|
|
@@ -1,12 +1,28 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "abbacus-cortex"
|
|
3
|
-
version = "0.2.
|
|
3
|
+
version = "0.2.2"
|
|
4
4
|
description = "Cognitive knowledge system with formal ontology, reasoning, and intelligence serving"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
authors = [
|
|
7
7
|
{ name = "Fabrizzio Silveira", email = "74255714+grayisnotacolor@users.noreply.github.com" }
|
|
8
8
|
]
|
|
9
|
+
license = "BUSL-1.1"
|
|
10
|
+
license-files = ["LICENSE"]
|
|
9
11
|
requires-python = ">=3.12"
|
|
12
|
+
keywords = ["knowledge-graph", "knowledge-management", "mcp", "reasoning", "ontology", "rdf", "ai", "semantic-search", "llm"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 4 - Beta",
|
|
15
|
+
"Environment :: Console",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: Other/Proprietary License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.12",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
22
|
+
"Topic :: Database :: Database Engines/Servers",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
|
|
10
26
|
dependencies = [
|
|
11
27
|
# Graph / Ontology
|
|
12
28
|
"pyoxigraph>=0.4",
|
|
@@ -27,11 +43,19 @@ dependencies = [
|
|
|
27
43
|
"mcp>=1.6",
|
|
28
44
|
# HTTP client
|
|
29
45
|
"httpx>=0.28",
|
|
46
|
+
# LLM (provider-agnostic: Anthropic, OpenAI, Ollama, etc.)
|
|
47
|
+
"litellm>=1.60",
|
|
30
48
|
]
|
|
31
49
|
|
|
50
|
+
[project.urls]
|
|
51
|
+
Homepage = "https://github.com/abbacusgroup/Cortex"
|
|
52
|
+
Repository = "https://github.com/abbacusgroup/Cortex"
|
|
53
|
+
Documentation = "https://github.com/abbacusgroup/Cortex#readme"
|
|
54
|
+
Changelog = "https://github.com/abbacusgroup/Cortex/blob/main/CHANGELOG.md"
|
|
55
|
+
"Bug Tracker" = "https://github.com/abbacusgroup/Cortex/issues"
|
|
56
|
+
|
|
32
57
|
[project.optional-dependencies]
|
|
33
58
|
embeddings = ["sentence-transformers>=3.4"]
|
|
34
|
-
llm = ["litellm>=1.60"]
|
|
35
59
|
|
|
36
60
|
[project.scripts]
|
|
37
61
|
cortex = "cortex.cli.main:app"
|
|
@@ -57,11 +81,12 @@ build-backend = "uv_build"
|
|
|
57
81
|
build-backend.module-name = "cortex"
|
|
58
82
|
|
|
59
83
|
[tool.pytest.ini_options]
|
|
60
|
-
testpaths = ["tests"]
|
|
84
|
+
testpaths = ["tests", "benchmarks"]
|
|
61
85
|
asyncio_mode = "auto"
|
|
62
86
|
pythonpath = ["src"]
|
|
63
87
|
markers = [
|
|
64
88
|
"slow: end-to-end tests that spawn subprocesses (skipped in fast loops)",
|
|
89
|
+
"bench: benchmark suite (run with -m bench)",
|
|
65
90
|
]
|
|
66
91
|
|
|
67
92
|
[tool.ruff]
|
|
Binary file
|
|
@@ -21,13 +21,15 @@ from cortex.core.config import CortexConfig
|
|
|
21
21
|
# ---------------------------------------------------------------------------
|
|
22
22
|
|
|
23
23
|
# Relative paths (from data_dir) to exclude from backup archives.
|
|
24
|
-
_EXCLUDE_EXACT = frozenset(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
24
|
+
_EXCLUDE_EXACT = frozenset(
|
|
25
|
+
{
|
|
26
|
+
"graph.db.lock",
|
|
27
|
+
"graph.db/LOCK",
|
|
28
|
+
".env",
|
|
29
|
+
"cortex.db-wal",
|
|
30
|
+
"cortex.db-shm",
|
|
31
|
+
}
|
|
32
|
+
)
|
|
31
33
|
|
|
32
34
|
_EXCLUDE_SUFFIXES = (".log", ".err", ".log.old", ".err.old")
|
|
33
35
|
|
|
@@ -294,6 +294,13 @@ def _unit_name(label: str) -> str:
|
|
|
294
294
|
|
|
295
295
|
def _install_systemd_unit(label: str, content: str) -> Path:
|
|
296
296
|
"""Write a unit file and enable it."""
|
|
297
|
+
if not shutil.which("systemctl"):
|
|
298
|
+
typer.echo(
|
|
299
|
+
" Error: systemctl not found — systemd is required for service install on Linux"
|
|
300
|
+
)
|
|
301
|
+
typer.echo(" You can still run Cortex manually: cortex serve --transport mcp-http")
|
|
302
|
+
raise typer.Exit(1)
|
|
303
|
+
|
|
297
304
|
_SYSTEMD_USER_DIR.mkdir(parents=True, exist_ok=True)
|
|
298
305
|
unit_path = _SYSTEMD_USER_DIR / _unit_name(label)
|
|
299
306
|
unit_name = unit_path.name
|
|
@@ -322,11 +329,12 @@ def _uninstall_systemd_unit(label: str) -> None:
|
|
|
322
329
|
if not unit_path.exists():
|
|
323
330
|
typer.echo(f" {unit_name}: not installed")
|
|
324
331
|
return
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
332
|
+
if shutil.which("systemctl"):
|
|
333
|
+
subprocess.run(
|
|
334
|
+
["systemctl", "--user", "disable", "--now", unit_name],
|
|
335
|
+
check=False,
|
|
336
|
+
capture_output=True,
|
|
337
|
+
)
|
|
330
338
|
unit_path.unlink()
|
|
331
339
|
subprocess.run(
|
|
332
340
|
["systemctl", "--user", "daemon-reload"],
|
|
@@ -357,16 +365,12 @@ def do_install(config: CortexConfig, service: str) -> None:
|
|
|
357
365
|
if svc == "mcp":
|
|
358
366
|
_install_launchagent(_MCP_LABEL, render_mcp_plist(config, binary))
|
|
359
367
|
else:
|
|
360
|
-
_install_launchagent(
|
|
361
|
-
_DASHBOARD_LABEL, render_dashboard_plist(config, binary)
|
|
362
|
-
)
|
|
368
|
+
_install_launchagent(_DASHBOARD_LABEL, render_dashboard_plist(config, binary))
|
|
363
369
|
else:
|
|
364
370
|
if svc == "mcp":
|
|
365
371
|
_install_systemd_unit(_MCP_LABEL, render_mcp_unit(config, binary))
|
|
366
372
|
else:
|
|
367
|
-
_install_systemd_unit(
|
|
368
|
-
_DASHBOARD_LABEL, render_dashboard_unit(config, binary)
|
|
369
|
-
)
|
|
373
|
+
_install_systemd_unit(_DASHBOARD_LABEL, render_dashboard_unit(config, binary))
|
|
370
374
|
|
|
371
375
|
typer.echo()
|
|
372
376
|
if "mcp" in services:
|
|
@@ -574,7 +574,9 @@ def status() -> None:
|
|
|
574
574
|
store = _get_store(must_init=False)
|
|
575
575
|
stats = store.status()
|
|
576
576
|
|
|
577
|
-
|
|
577
|
+
from cortex import __version__
|
|
578
|
+
|
|
579
|
+
typer.echo(f"Cortex v{__version__}")
|
|
578
580
|
typer.echo(f" Initialized: {stats['initialized']}")
|
|
579
581
|
typer.echo(f" Documents: {stats['sqlite_total']}")
|
|
580
582
|
typer.echo(f" Triples: {stats['graph_triples']}")
|
|
@@ -594,9 +596,7 @@ def context(
|
|
|
594
596
|
) -> None:
|
|
595
597
|
"""Get a briefing (summaries only) for a topic."""
|
|
596
598
|
if _use_mcp():
|
|
597
|
-
briefs = _mcp_call_or_exit(
|
|
598
|
-
lambda: _get_mcp_client().context(topic=topic, limit=limit)
|
|
599
|
-
)
|
|
599
|
+
briefs = _mcp_call_or_exit(lambda: _get_mcp_client().context(topic=topic, limit=limit))
|
|
600
600
|
else:
|
|
601
601
|
store = _get_store()
|
|
602
602
|
from cortex.retrieval.engine import RetrievalEngine
|
|
@@ -624,9 +624,7 @@ def dossier(
|
|
|
624
624
|
) -> None:
|
|
625
625
|
"""Build an intelligence dossier around an entity or topic."""
|
|
626
626
|
if _use_mcp():
|
|
627
|
-
result = _mcp_call_or_exit(
|
|
628
|
-
lambda: _get_mcp_client().dossier(topic=topic)
|
|
629
|
-
)
|
|
627
|
+
result = _mcp_call_or_exit(lambda: _get_mcp_client().dossier(topic=topic))
|
|
630
628
|
else:
|
|
631
629
|
store = _get_store()
|
|
632
630
|
from cortex.retrieval.presenters import DossierPresenter
|
|
@@ -671,9 +669,7 @@ def graph(
|
|
|
671
669
|
) -> None:
|
|
672
670
|
"""Show an object's relationships and graph neighborhood."""
|
|
673
671
|
if _use_mcp():
|
|
674
|
-
result = _mcp_call_or_exit(
|
|
675
|
-
lambda: _get_mcp_client().graph(obj_id=obj_id)
|
|
676
|
-
)
|
|
672
|
+
result = _mcp_call_or_exit(lambda: _get_mcp_client().graph(obj_id=obj_id))
|
|
677
673
|
chain = result.get("causal_chain", [])
|
|
678
674
|
timeline = result.get("evolution", [])
|
|
679
675
|
rels = result.get("relationships", [])
|
|
@@ -719,9 +715,7 @@ def synthesize(
|
|
|
719
715
|
"""Generate a synthesis of recent knowledge."""
|
|
720
716
|
if _use_mcp():
|
|
721
717
|
result = _mcp_call_or_exit(
|
|
722
|
-
lambda: _get_mcp_client().synthesize(
|
|
723
|
-
period_days=period, project=project or ""
|
|
724
|
-
)
|
|
718
|
+
lambda: _get_mcp_client().synthesize(period_days=period, project=project or "")
|
|
725
719
|
)
|
|
726
720
|
else:
|
|
727
721
|
store = _get_store()
|
|
@@ -966,6 +960,7 @@ def serve(
|
|
|
966
960
|
"""
|
|
967
961
|
if transport == "stdio":
|
|
968
962
|
from cortex.transport.mcp.server import run_stdio
|
|
963
|
+
|
|
969
964
|
try:
|
|
970
965
|
run_stdio()
|
|
971
966
|
except StoreLockedError as e:
|
|
@@ -973,6 +968,7 @@ def serve(
|
|
|
973
968
|
raise typer.Exit(1) from e
|
|
974
969
|
elif transport == "mcp-http":
|
|
975
970
|
from cortex.transport.mcp.server import run_http
|
|
971
|
+
|
|
976
972
|
typer.echo(f"Cortex MCP (streamable-http) at http://{host}:{port}/mcp")
|
|
977
973
|
if parent_watchdog:
|
|
978
974
|
_start_parent_watchdog()
|
|
@@ -1096,6 +1092,7 @@ def setup(
|
|
|
1096
1092
|
typer.echo(f" LLM: {config.llm_model}")
|
|
1097
1093
|
try:
|
|
1098
1094
|
from cortex.services.llm import LLMClient
|
|
1095
|
+
|
|
1099
1096
|
llm = LLMClient(config)
|
|
1100
1097
|
llm.complete("Say 'connected' in one word.")
|
|
1101
1098
|
typer.echo(" LLM: Connected")
|
|
@@ -1378,15 +1375,12 @@ def dashboard(
|
|
|
1378
1375
|
|
|
1379
1376
|
# --spawn-mcp: launch the MCP server as a subprocess and wait.
|
|
1380
1377
|
typer.secho(
|
|
1381
|
-
f"MCP server at {config.mcp_server_url} unreachable — "
|
|
1382
|
-
f"spawning one via --spawn-mcp…",
|
|
1378
|
+
f"MCP server at {config.mcp_server_url} unreachable — spawning one via --spawn-mcp…",
|
|
1383
1379
|
fg=typer.colors.YELLOW,
|
|
1384
1380
|
err=True,
|
|
1385
1381
|
)
|
|
1386
1382
|
try:
|
|
1387
|
-
spawned_proc = _spawn_mcp_subprocess(
|
|
1388
|
-
config.mcp_server_url, config.data_dir
|
|
1389
|
-
)
|
|
1383
|
+
spawned_proc = _spawn_mcp_subprocess(config.mcp_server_url, config.data_dir)
|
|
1390
1384
|
except RuntimeError as spawn_err:
|
|
1391
1385
|
typer.secho(
|
|
1392
1386
|
f"Failed to spawn MCP subprocess: {spawn_err}",
|
|
@@ -1506,9 +1500,7 @@ def run_pipeline_cmd(
|
|
|
1506
1500
|
raise typer.Exit(1)
|
|
1507
1501
|
|
|
1508
1502
|
if _use_mcp():
|
|
1509
|
-
result = _mcp_call_or_exit(
|
|
1510
|
-
lambda: _get_mcp_client().pipeline(obj_id=obj_id)
|
|
1511
|
-
)
|
|
1503
|
+
result = _mcp_call_or_exit(lambda: _get_mcp_client().pipeline(obj_id=obj_id))
|
|
1512
1504
|
if "error" in result:
|
|
1513
1505
|
typer.echo(result["error"], err=True)
|
|
1514
1506
|
raise typer.Exit(1)
|
|
@@ -1635,15 +1627,10 @@ def doctor_unlock(
|
|
|
1635
1627
|
if dry_run:
|
|
1636
1628
|
typer.echo("Dry run — no files will be removed.")
|
|
1637
1629
|
typer.echo(f" marker: {marker_path} (exists={marker_path.exists()})")
|
|
1638
|
-
typer.echo(
|
|
1639
|
-
f" rocksdb LOCK: {rocksdb_lock} (exists={rocksdb_lock.exists()})"
|
|
1640
|
-
)
|
|
1630
|
+
typer.echo(f" rocksdb LOCK: {rocksdb_lock} (exists={rocksdb_lock.exists()})")
|
|
1641
1631
|
if holder_pid is not None:
|
|
1642
1632
|
alive = _pid_alive(holder_pid)
|
|
1643
|
-
typer.echo(
|
|
1644
|
-
f" holder PID: {holder_pid} "
|
|
1645
|
-
f"({'alive' if alive else 'dead'})"
|
|
1646
|
-
)
|
|
1633
|
+
typer.echo(f" holder PID: {holder_pid} ({'alive' if alive else 'dead'})")
|
|
1647
1634
|
if holder_cmdline:
|
|
1648
1635
|
typer.echo(f" holder cmdline: {holder_cmdline}")
|
|
1649
1636
|
raise typer.Exit(0)
|
|
@@ -1689,8 +1676,7 @@ def doctor_unlock(
|
|
|
1689
1676
|
rocksdb_lock.unlink(missing_ok=True)
|
|
1690
1677
|
removed.append(str(rocksdb_lock))
|
|
1691
1678
|
typer.secho(
|
|
1692
|
-
f"Unlocked. No holder PID known; removed: "
|
|
1693
|
-
f"{', '.join(removed) or 'nothing'}",
|
|
1679
|
+
f"Unlocked. No holder PID known; removed: {', '.join(removed) or 'nothing'}",
|
|
1694
1680
|
fg=typer.colors.GREEN,
|
|
1695
1681
|
)
|
|
1696
1682
|
raise typer.Exit(0)
|
|
@@ -1703,9 +1689,7 @@ def doctor_unlock(
|
|
|
1703
1689
|
and holder_cmdline is not None
|
|
1704
1690
|
and live_cmdline != holder_cmdline
|
|
1705
1691
|
)
|
|
1706
|
-
cmdline_unknown =
|
|
1707
|
-
live_cmdline is None and holder_cmdline is not None
|
|
1708
|
-
)
|
|
1692
|
+
cmdline_unknown = live_cmdline is None and holder_cmdline is not None
|
|
1709
1693
|
if is_reuse:
|
|
1710
1694
|
typer.secho(
|
|
1711
1695
|
f"PID {holder_pid} is alive but its cmdline does NOT match "
|
|
@@ -1727,14 +1711,12 @@ def doctor_unlock(
|
|
|
1727
1711
|
err=True,
|
|
1728
1712
|
)
|
|
1729
1713
|
typer.echo(
|
|
1730
|
-
" If you are sure the marker is stale, run: "
|
|
1731
|
-
"cortex doctor unlock --force",
|
|
1714
|
+
" If you are sure the marker is stale, run: cortex doctor unlock --force",
|
|
1732
1715
|
err=True,
|
|
1733
1716
|
)
|
|
1734
1717
|
else:
|
|
1735
1718
|
typer.secho(
|
|
1736
|
-
f"PID {holder_pid} is still running — refusing to unlock "
|
|
1737
|
-
f"a live holder.",
|
|
1719
|
+
f"PID {holder_pid} is still running — refusing to unlock a live holder.",
|
|
1738
1720
|
fg=typer.colors.RED,
|
|
1739
1721
|
err=True,
|
|
1740
1722
|
)
|
|
@@ -1757,8 +1739,7 @@ def doctor_unlock(
|
|
|
1757
1739
|
raise typer.Exit(1)
|
|
1758
1740
|
|
|
1759
1741
|
typer.secho(
|
|
1760
|
-
f"Unlocked. Holder PID {holder_pid} was dead; removed "
|
|
1761
|
-
f"{marker_path} and {rocksdb_lock}.",
|
|
1742
|
+
f"Unlocked. Holder PID {holder_pid} was dead; removed {marker_path} and {rocksdb_lock}.",
|
|
1762
1743
|
fg=typer.colors.GREEN,
|
|
1763
1744
|
)
|
|
1764
1745
|
|
|
@@ -1777,7 +1758,7 @@ _LAUNCHAGENT_LOG_FILENAMES = (
|
|
|
1777
1758
|
)
|
|
1778
1759
|
|
|
1779
1760
|
# Size thresholds for the summary status badge.
|
|
1780
|
-
_LOG_SIZE_GREEN_MAX = 10 * 1024 * 1024
|
|
1761
|
+
_LOG_SIZE_GREEN_MAX = 10 * 1024 * 1024 # 10 MB
|
|
1781
1762
|
_LOG_SIZE_YELLOW_MAX = 100 * 1024 * 1024 # 100 MB
|
|
1782
1763
|
|
|
1783
1764
|
|
|
@@ -1840,9 +1821,7 @@ def _summarize_logs(log_paths: list[Path]) -> None:
|
|
|
1840
1821
|
stat = path.stat()
|
|
1841
1822
|
size_bytes = stat.st_size
|
|
1842
1823
|
lines = _count_lines(path)
|
|
1843
|
-
mtime = datetime.datetime.fromtimestamp(stat.st_mtime).strftime(
|
|
1844
|
-
"%Y-%m-%d %H:%M:%S"
|
|
1845
|
-
)
|
|
1824
|
+
mtime = datetime.datetime.fromtimestamp(stat.st_mtime).strftime("%Y-%m-%d %H:%M:%S")
|
|
1846
1825
|
color = _log_status_color(size_bytes)
|
|
1847
1826
|
label = _log_status_label(size_bytes)
|
|
1848
1827
|
typer.echo(
|
|
@@ -2015,9 +1994,7 @@ def doctor_check() -> None:
|
|
|
2015
1994
|
try:
|
|
2016
1995
|
fts = content.fts_integrity_check()
|
|
2017
1996
|
if fts["ok"]:
|
|
2018
|
-
typer.echo(
|
|
2019
|
-
f" FTS5 index: OK ({fts['documents_count']} documents indexed)"
|
|
2020
|
-
)
|
|
1997
|
+
typer.echo(f" FTS5 index: OK ({fts['documents_count']} documents indexed)")
|
|
2021
1998
|
else:
|
|
2022
1999
|
all_ok = False
|
|
2023
2000
|
typer.secho(
|
|
@@ -2042,8 +2019,7 @@ def doctor_check() -> None:
|
|
|
2042
2019
|
else:
|
|
2043
2020
|
all_ok = False
|
|
2044
2021
|
typer.secho(
|
|
2045
|
-
f" Reasoner: WARN — {fixpoint['total_pending']} "
|
|
2046
|
-
"triples pending inference",
|
|
2022
|
+
f" Reasoner: WARN — {fixpoint['total_pending']} triples pending inference",
|
|
2047
2023
|
fg=typer.colors.YELLOW,
|
|
2048
2024
|
)
|
|
2049
2025
|
typer.echo(" Run `cortex doctor repair` to reach fixpoint.")
|
|
@@ -2113,9 +2089,7 @@ def doctor_repair() -> None:
|
|
|
2113
2089
|
content = ContentStore(path=config.sqlite_db_path)
|
|
2114
2090
|
try:
|
|
2115
2091
|
result = content.fts_rebuild()
|
|
2116
|
-
typer.echo(
|
|
2117
|
-
f" FTS5 index: rebuilt ({result['documents_count']} documents reindexed)"
|
|
2118
|
-
)
|
|
2092
|
+
typer.echo(f" FTS5 index: rebuilt ({result['documents_count']} documents reindexed)")
|
|
2119
2093
|
finally:
|
|
2120
2094
|
content.close()
|
|
2121
2095
|
|
|
@@ -19,36 +19,42 @@ DEFAULT_HOST = "127.0.0.1"
|
|
|
19
19
|
DEFAULT_PORT = 1314
|
|
20
20
|
|
|
21
21
|
# Knowledge object types (must match ontology classes)
|
|
22
|
-
KNOWLEDGE_TYPES = frozenset(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
22
|
+
KNOWLEDGE_TYPES = frozenset(
|
|
23
|
+
{
|
|
24
|
+
"decision",
|
|
25
|
+
"lesson",
|
|
26
|
+
"fix",
|
|
27
|
+
"session",
|
|
28
|
+
"research",
|
|
29
|
+
"source",
|
|
30
|
+
"synthesis",
|
|
31
|
+
"idea",
|
|
32
|
+
}
|
|
33
|
+
)
|
|
32
34
|
|
|
33
35
|
# Relationship types (must match ontology object properties)
|
|
34
|
-
RELATIONSHIP_TYPES = frozenset(
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
RELATIONSHIP_TYPES = frozenset(
|
|
37
|
+
{
|
|
38
|
+
"causedBy",
|
|
39
|
+
"contradicts",
|
|
40
|
+
"supports",
|
|
41
|
+
"supersedes",
|
|
42
|
+
"dependsOn",
|
|
43
|
+
"ledTo",
|
|
44
|
+
"implements",
|
|
45
|
+
"mentions",
|
|
46
|
+
}
|
|
47
|
+
)
|
|
44
48
|
|
|
45
49
|
# Entity subtypes
|
|
46
|
-
ENTITY_TYPES = frozenset(
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
50
|
+
ENTITY_TYPES = frozenset(
|
|
51
|
+
{
|
|
52
|
+
"technology",
|
|
53
|
+
"project",
|
|
54
|
+
"pattern",
|
|
55
|
+
"concept",
|
|
56
|
+
}
|
|
57
|
+
)
|
|
52
58
|
|
|
53
59
|
# Tiers
|
|
54
60
|
TIERS = frozenset({"archive", "recall", "reflex"})
|