matimo-core 0.1.3__tar.gz → 0.2.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 (109) hide show
  1. {matimo_core-0.1.3 → matimo_core-0.2.0}/.gitignore +3 -1
  2. matimo_core-0.2.0/LICENSE +21 -0
  3. {matimo_core-0.1.3 → matimo_core-0.2.0}/PKG-INFO +35 -17
  4. {matimo_core-0.1.3 → matimo_core-0.2.0}/README.md +27 -14
  5. {matimo_core-0.1.3 → matimo_core-0.2.0}/pyproject.toml +7 -4
  6. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/__init__.py +56 -6
  7. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/approval/handler.py +74 -17
  8. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/auth/injection.py +34 -27
  9. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/auth/oauth2_handler.py +3 -3
  10. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/loader.py +3 -2
  11. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/models.py +6 -0
  12. matimo_core-0.2.0/src/matimo/core/response_size_guardrail.py +150 -0
  13. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/skill_content_parser.py +28 -9
  14. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/skill_loader.py +1 -1
  15. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/skill_registry.py +6 -5
  16. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/decorators/__init__.py +3 -1
  17. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/errors.py +22 -3
  18. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/executors/function_executor.py +50 -7
  19. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/executors/http_executor.py +51 -14
  20. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/instance.py +467 -50
  21. matimo_core-0.2.0/src/matimo/integrations/_async_bridge.py +65 -0
  22. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/integrations/_pydantic_utils.py +50 -20
  23. matimo_core-0.2.0/src/matimo/integrations/agno.py +407 -0
  24. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/integrations/crewai.py +106 -6
  25. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/integrations/langchain.py +17 -4
  26. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/logging/__init__.py +8 -7
  27. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/README.md +39 -44
  28. matimo_core-0.2.0/src/matimo/mcp/approval_elicitation.py +90 -0
  29. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/secrets/__init__.py +4 -4
  30. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/server.py +227 -63
  31. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/tool_converter.py +96 -8
  32. matimo_core-0.2.0/src/matimo/policy/audit_sink.py +179 -0
  33. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/content_validator.py +24 -21
  34. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/default_policy.py +36 -16
  35. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/policy_loader.py +7 -2
  36. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/risk_classifier.py +33 -6
  37. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/types.py +48 -1
  38. matimo_core-0.2.0/src/matimo/skills/meta-tools-lifecycle/SKILL.md +306 -0
  39. matimo_core-0.2.0/src/matimo/skills/policy-validation/SKILL.md +233 -0
  40. matimo_core-0.2.0/src/matimo/skills/skill-creator/SKILL.md +439 -0
  41. matimo_core-0.2.0/src/matimo/skills/skills-catalog/SKILL.md +191 -0
  42. matimo_core-0.2.0/src/matimo/skills/tool-creation/SKILL.md +303 -0
  43. matimo_core-0.2.0/src/matimo/skills/tool-discovery/SKILL.md +176 -0
  44. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/calculator/definition.yaml +1 -0
  45. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/convert_to_file/definition.yaml +1 -0
  46. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/edit/definition.yaml +1 -0
  47. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/execute/definition.yaml +3 -0
  48. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/extract_from_file/definition.yaml +1 -0
  49. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_approve_tool/definition.yaml +2 -1
  50. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_approve_tool/matimo_approve_tool.py +56 -2
  51. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_create_skill/definition.yaml +1 -0
  52. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_create_skill/matimo_create_skill.py +24 -2
  53. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_create_tool/definition.yaml +1 -0
  54. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_create_tool/matimo_create_tool.py +19 -5
  55. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_skill/definition.yaml +1 -0
  56. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_skill/matimo_get_skill.py +3 -2
  57. matimo_core-0.2.0/src/matimo/tools/matimo_get_skill_content/definition.yaml +57 -0
  58. matimo_core-0.2.0/src/matimo/tools/matimo_get_skill_content/matimo_get_skill_content.py +63 -0
  59. matimo_core-0.2.0/src/matimo/tools/matimo_get_skill_sections/definition.yaml +37 -0
  60. matimo_core-0.2.0/src/matimo/tools/matimo_get_skill_sections/matimo_get_skill_sections.py +48 -0
  61. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_tool/definition.yaml +1 -0
  62. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_tool_status/definition.yaml +1 -0
  63. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_tool_status/matimo_get_tool_status.py +18 -3
  64. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_list_skills/definition.yaml +1 -0
  65. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_list_skills/matimo_list_skills.py +13 -12
  66. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_list_user_tools/definition.yaml +1 -0
  67. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_list_user_tools/matimo_list_user_tools.py +2 -1
  68. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_reload_tools/definition.yaml +1 -0
  69. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_reload_tools/matimo_reload_tools.py +2 -1
  70. matimo_core-0.2.0/src/matimo/tools/matimo_search_skills/definition.yaml +46 -0
  71. matimo_core-0.2.0/src/matimo/tools/matimo_search_skills/matimo_search_skills.py +53 -0
  72. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_search_tools/definition.yaml +1 -0
  73. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_search_tools/matimo_search_tools.py +2 -1
  74. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_validate_skill/definition.yaml +1 -0
  75. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_validate_tool/definition.yaml +1 -0
  76. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_validate_tool/matimo_validate_tool.py +15 -3
  77. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/read/definition.yaml +1 -0
  78. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/search/definition.yaml +3 -0
  79. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/web/definition.yaml +1 -0
  80. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/web_scraper/definition.yaml +1 -0
  81. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/approval/__init__.py +0 -0
  82. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/auth/__init__.py +0 -0
  83. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/auth/oauth2_config.py +0 -0
  84. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/auth/oauth2_provider_loader.py +0 -0
  85. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/__init__.py +0 -0
  86. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/registry.py +0 -0
  87. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/core/tfidf_embedding.py +0 -0
  88. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/encodings/__init__.py +0 -0
  89. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/encodings/parameter_encoding.py +0 -0
  90. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/executors/__init__.py +0 -0
  91. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/executors/command_executor.py +0 -0
  92. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/integrations/__init__.py +0 -0
  93. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/__init__.py +0 -0
  94. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/mcp/secrets/types.py +0 -0
  95. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/__init__.py +0 -0
  96. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/approval_manifest.py +0 -0
  97. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/policy/integrity_tracker.py +0 -0
  98. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/sync.py +0 -0
  99. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/calculator/calculator.py +0 -0
  100. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/convert_to_file/convert_to_file.py +0 -0
  101. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/edit/edit.py +0 -0
  102. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/execute/execute.py +0 -0
  103. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/extract_from_file/extract_from_file.py +0 -0
  104. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_get_tool/matimo_get_tool.py +0 -0
  105. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/matimo_validate_skill/matimo_validate_skill.py +0 -0
  106. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/read/read.py +0 -0
  107. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/search/search.py +0 -0
  108. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/web/web.py +0 -0
  109. {matimo_core-0.1.3 → matimo_core-0.2.0}/src/matimo/tools/web_scraper/web_scraper.py +0 -0
@@ -58,7 +58,6 @@ temp/
58
58
 
59
59
  # Personal scratch notes / working docs — not part of the shipped repo
60
60
  .local-notes/
61
- typescript/examples/mcp/matimo-tools/.matimo-approvals.json
62
61
  typescript/examples/mcp/matimo-tools/fetch-weather/definition.yaml
63
62
  typescript/examples/mcp/matimo-tools/npm_downloads/definition.yaml
64
63
  typescript/examples/mcp/matimo-tools/skills/ecosystem-health/SKILL.md
@@ -68,3 +67,6 @@ typescript/packages/cli/.matimo/certs/server.crt
68
67
  typescript/packages/cli/.matimo/certs/server.key
69
68
  typescript/examples/mcp/.matimo/certs/server.crt
70
69
  typescript/examples/mcp/.matimo/certs/server.key
70
+
71
+ # HITL approval manifests are per-machine state (HMAC-signed approvals); never commit one
72
+ **/.matimo-approvals.json
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ROAIQ TECHNOLOGIES PRIVATE LIMITED
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,13 +1,14 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: matimo-core
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: Matimo core — framework-agnostic SDK: pre-built providers, skills layer, MCP, and a policy engine you control
5
5
  Project-URL: Homepage, https://matimo.dev
6
- Project-URL: Documentation, https://matimo.dev/docs
6
+ Project-URL: Documentation, https://docs.matimo.dev/
7
7
  Project-URL: Repository, https://github.com/tallclub/matimo
8
8
  Project-URL: Issues, https://github.com/tallclub/matimo/issues
9
9
  License: MIT
10
- Keywords: agentic-ai,agents,ai,ai-governance,crewai,langchain,matimo,mcp,mcp-server,policy-engine,tools
10
+ License-File: LICENSE
11
+ Keywords: agentic-ai,agents,agno,ai,ai-governance,crewai,langchain,matimo,mcp,mcp-server,policy-engine,tools
11
12
  Classifier: Development Status :: 4 - Beta
12
13
  Classifier: Intended Audience :: Developers
13
14
  Classifier: License :: OSI Approved :: MIT License
@@ -31,7 +32,10 @@ Requires-Dist: readability-lxml>=0.8.4.1
31
32
  Requires-Dist: reportlab>=4.0
32
33
  Requires-Dist: simpleeval>=1.0
33
34
  Requires-Dist: typing-extensions>=4.9
35
+ Provides-Extra: agno
36
+ Requires-Dist: agno>=3.0; extra == 'agno'
34
37
  Provides-Extra: all
38
+ Requires-Dist: agno>=3.0; extra == 'all'
35
39
  Requires-Dist: crewai>=0.80; extra == 'all'
36
40
  Requires-Dist: hvac>=2.0; extra == 'all'
37
41
  Requires-Dist: langchain-core>=0.3; extra == 'all'
@@ -42,6 +46,7 @@ Requires-Dist: boto3>=1.34; extra == 'aws'
42
46
  Provides-Extra: crewai
43
47
  Requires-Dist: crewai>=0.80; extra == 'crewai'
44
48
  Provides-Extra: dev
49
+ Requires-Dist: agno>=3.0; extra == 'dev'
45
50
  Requires-Dist: boto3>=1.34; extra == 'dev'
46
51
  Requires-Dist: crewai>=0.80; extra == 'dev'
47
52
  Requires-Dist: hvac>=2.0; extra == 'dev'
@@ -71,7 +76,7 @@ Description-Content-Type: text/markdown
71
76
 
72
77
  [![PyPI](https://img.shields.io/pypi/v/matimo-core)](https://pypi.org/project/matimo-core/)
73
78
  [![Python](https://img.shields.io/pypi/pyversions/matimo-core)](https://pypi.org/project/matimo-core/)
74
- [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://matimo.dev/docs)
79
+ [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://docs.matimo.dev)
75
80
  [![Tests](https://img.shields.io/badge/tests-1134%20passing-brightgreen)](https://github.com/tallclub/matimo)
76
81
  [![Coverage](https://img.shields.io/badge/coverage-97%25-brightgreen)](https://github.com/tallclub/matimo)
77
82
 
@@ -188,7 +193,7 @@ await server.start()
188
193
  ### `Matimo.init()`
189
194
 
190
195
  ```python
191
- from matimo import Matimo, InitOptions
196
+ from matimo import InitOptions, JsonlFileSink, Matimo
192
197
 
193
198
  matimo = await Matimo.init(
194
199
  tool_paths=['./tools', './agent-tools'], # or a single string
@@ -199,6 +204,7 @@ matimo = await Matimo.init(
199
204
  log_level='info', # silent | error | warn | info | debug
200
205
  log_format='json', # json | simple
201
206
  on_event=my_event_handler,
207
+ audit_sink=JsonlFileSink('./logs/matimo-audit.jsonl'), # hash-chained audit log
202
208
  on_hitl=my_approval_callback,
203
209
  )
204
210
  ```
@@ -242,14 +248,23 @@ execution:
242
248
  ## Policy Engine
243
249
 
244
250
  ```python
245
- from matimo import Matimo, InitOptions
251
+ from matimo import ApprovalRequest, JsonlFileSink, Matimo
246
252
 
247
- matimo = await Matimo.init('./tools', InitOptions(
253
+
254
+ async def ask_operator(request: ApprovalRequest) -> bool:
255
+ return input(f"Approve {request.tool_name} {request.params}? (y/n) ") == "y"
256
+
257
+
258
+ matimo = await Matimo.init(
259
+ './tools',
248
260
  policy_file='./policy.yaml',
249
- on_hitl=lambda req: {'approved': True, 'reason': 'auto'},
250
- ))
261
+ on_approval=ask_operator, # calls that need approval ask here
262
+ audit_sink=JsonlFileSink('./matimo-audit.jsonl'), # hash-chained audit log
263
+ )
251
264
  ```
252
265
 
266
+ Calls that need approval: tools with `requires_approval: true`, HTTP `DELETE` and command tools (the 0.2.0 secure default), and calls whose `sql`/`command` argument contains a destructive keyword. With no `on_approval` they are refused.
267
+
253
268
  `policy.yaml`:
254
269
  ```yaml
255
270
  allowedDomains:
@@ -309,25 +324,28 @@ Built-in tools that let agents manage other tools at runtime:
309
324
  | `matimo_list_skills` | List available skills | No |
310
325
  | `matimo_get_skill` | Read skill content | No |
311
326
  | `matimo_validate_skill` | Validate skill spec | No |
327
+ | `matimo_search_skills` | Semantically rank skills by relevance (TF-IDF) | No |
328
+ | `matimo_get_skill_sections` | Inventory a skill's sections and token costs | No |
329
+ | `matimo_get_skill_content` | Load only specific sections of a skill | No |
312
330
 
313
331
  ---
314
332
 
315
333
  ## Documentation
316
334
 
317
- - [Getting Started](https://matimo.dev/docs/getting-started/QUICK_START)
318
- - [Full API Reference](https://matimo.dev/docs/api-reference/SDK)
319
- - [LangChain Integration](https://matimo.dev/docs/framework-integrations/LANGCHAIN)
320
- - [CrewAI Integration](https://matimo.dev/docs/framework-integrations/CREWAI)
321
- - [MCP Guide](https://matimo.dev/docs/MCP)
322
- - [Policy & Lifecycle](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE)
323
- - [Meta-Tools Reference](https://matimo.dev/docs/api-reference/META_TOOLS)
335
+ - [Getting Started](https://docs.matimo.dev/getting-started/QUICK_START)
336
+ - [Full API Reference](https://docs.matimo.dev/api-reference/SDK)
337
+ - [LangChain Integration](https://docs.matimo.dev/framework-integrations/LANGCHAIN)
338
+ - [CrewAI Integration](https://docs.matimo.dev/framework-integrations/CREWAI)
339
+ - [MCP Guide](https://docs.matimo.dev/MCP)
340
+ - [Policy & Lifecycle](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE)
341
+ - [Meta-Tools Reference](https://docs.matimo.dev/api-reference/META_TOOLS)
324
342
 
325
343
  ---
326
344
 
327
345
  ## Links
328
346
 
329
347
  - **PyPI:** https://pypi.org/project/matimo-core/
330
- - **Docs:** https://matimo.dev/docs
348
+ - **Docs:** https://docs.matimo.dev/
331
349
  - **GitHub:** https://github.com/tallclub/matimo
332
350
  - **Changelog:** https://github.com/tallclub/matimo/blob/main/docs/RELEASES.md
333
351
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![PyPI](https://img.shields.io/pypi/v/matimo-core)](https://pypi.org/project/matimo-core/)
6
6
  [![Python](https://img.shields.io/pypi/pyversions/matimo-core)](https://pypi.org/project/matimo-core/)
7
- [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://matimo.dev/docs)
7
+ [![Docs](https://img.shields.io/badge/docs-matimo.dev-blue)](https://docs.matimo.dev)
8
8
  [![Tests](https://img.shields.io/badge/tests-1134%20passing-brightgreen)](https://github.com/tallclub/matimo)
9
9
  [![Coverage](https://img.shields.io/badge/coverage-97%25-brightgreen)](https://github.com/tallclub/matimo)
10
10
 
@@ -121,7 +121,7 @@ await server.start()
121
121
  ### `Matimo.init()`
122
122
 
123
123
  ```python
124
- from matimo import Matimo, InitOptions
124
+ from matimo import InitOptions, JsonlFileSink, Matimo
125
125
 
126
126
  matimo = await Matimo.init(
127
127
  tool_paths=['./tools', './agent-tools'], # or a single string
@@ -132,6 +132,7 @@ matimo = await Matimo.init(
132
132
  log_level='info', # silent | error | warn | info | debug
133
133
  log_format='json', # json | simple
134
134
  on_event=my_event_handler,
135
+ audit_sink=JsonlFileSink('./logs/matimo-audit.jsonl'), # hash-chained audit log
135
136
  on_hitl=my_approval_callback,
136
137
  )
137
138
  ```
@@ -175,14 +176,23 @@ execution:
175
176
  ## Policy Engine
176
177
 
177
178
  ```python
178
- from matimo import Matimo, InitOptions
179
+ from matimo import ApprovalRequest, JsonlFileSink, Matimo
179
180
 
180
- matimo = await Matimo.init('./tools', InitOptions(
181
+
182
+ async def ask_operator(request: ApprovalRequest) -> bool:
183
+ return input(f"Approve {request.tool_name} {request.params}? (y/n) ") == "y"
184
+
185
+
186
+ matimo = await Matimo.init(
187
+ './tools',
181
188
  policy_file='./policy.yaml',
182
- on_hitl=lambda req: {'approved': True, 'reason': 'auto'},
183
- ))
189
+ on_approval=ask_operator, # calls that need approval ask here
190
+ audit_sink=JsonlFileSink('./matimo-audit.jsonl'), # hash-chained audit log
191
+ )
184
192
  ```
185
193
 
194
+ Calls that need approval: tools with `requires_approval: true`, HTTP `DELETE` and command tools (the 0.2.0 secure default), and calls whose `sql`/`command` argument contains a destructive keyword. With no `on_approval` they are refused.
195
+
186
196
  `policy.yaml`:
187
197
  ```yaml
188
198
  allowedDomains:
@@ -242,25 +252,28 @@ Built-in tools that let agents manage other tools at runtime:
242
252
  | `matimo_list_skills` | List available skills | No |
243
253
  | `matimo_get_skill` | Read skill content | No |
244
254
  | `matimo_validate_skill` | Validate skill spec | No |
255
+ | `matimo_search_skills` | Semantically rank skills by relevance (TF-IDF) | No |
256
+ | `matimo_get_skill_sections` | Inventory a skill's sections and token costs | No |
257
+ | `matimo_get_skill_content` | Load only specific sections of a skill | No |
245
258
 
246
259
  ---
247
260
 
248
261
  ## Documentation
249
262
 
250
- - [Getting Started](https://matimo.dev/docs/getting-started/QUICK_START)
251
- - [Full API Reference](https://matimo.dev/docs/api-reference/SDK)
252
- - [LangChain Integration](https://matimo.dev/docs/framework-integrations/LANGCHAIN)
253
- - [CrewAI Integration](https://matimo.dev/docs/framework-integrations/CREWAI)
254
- - [MCP Guide](https://matimo.dev/docs/MCP)
255
- - [Policy & Lifecycle](https://matimo.dev/docs/api-reference/POLICY_AND_LIFECYCLE)
256
- - [Meta-Tools Reference](https://matimo.dev/docs/api-reference/META_TOOLS)
263
+ - [Getting Started](https://docs.matimo.dev/getting-started/QUICK_START)
264
+ - [Full API Reference](https://docs.matimo.dev/api-reference/SDK)
265
+ - [LangChain Integration](https://docs.matimo.dev/framework-integrations/LANGCHAIN)
266
+ - [CrewAI Integration](https://docs.matimo.dev/framework-integrations/CREWAI)
267
+ - [MCP Guide](https://docs.matimo.dev/MCP)
268
+ - [Policy & Lifecycle](https://docs.matimo.dev/api-reference/POLICY_AND_LIFECYCLE)
269
+ - [Meta-Tools Reference](https://docs.matimo.dev/api-reference/META_TOOLS)
257
270
 
258
271
  ---
259
272
 
260
273
  ## Links
261
274
 
262
275
  - **PyPI:** https://pypi.org/project/matimo-core/
263
- - **Docs:** https://matimo.dev/docs
276
+ - **Docs:** https://docs.matimo.dev/
264
277
  - **GitHub:** https://github.com/tallclub/matimo
265
278
  - **Changelog:** https://github.com/tallclub/matimo/blob/main/docs/RELEASES.md
266
279
 
@@ -4,12 +4,12 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "matimo-core"
7
- version = "0.1.3"
7
+ version = "0.2.0"
8
8
  description = "Matimo core — framework-agnostic SDK: pre-built providers, skills layer, MCP, and a policy engine you control"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
11
11
  requires-python = ">=3.11"
12
- keywords = ["ai", "tools", "agents", "langchain", "crewai", "mcp", "matimo", "mcp-server", "agentic-ai", "ai-governance", "policy-engine"]
12
+ keywords = ["ai", "tools", "agents", "langchain", "crewai", "agno", "mcp", "matimo", "mcp-server", "agentic-ai", "ai-governance", "policy-engine"]
13
13
  classifiers = [
14
14
  "Development Status :: 4 - Beta",
15
15
  "Intended Audience :: Developers",
@@ -40,6 +40,7 @@ dependencies = [
40
40
  [project.optional-dependencies]
41
41
  langchain = ["langchain-core>=0.3"]
42
42
  crewai = ["crewai>=0.80"]
43
+ agno = ["agno>=3.0"]
43
44
  mcp = ["mcp>=1.28.1"]
44
45
  vault = ["hvac>=2.0"]
45
46
  aws = ["boto3>=1.34"]
@@ -47,6 +48,7 @@ dotenv = ["python-dotenv>=1.0"]
47
48
  all = [
48
49
  "langchain-core>=0.3",
49
50
  "crewai>=0.80",
51
+ "agno>=3.0",
50
52
  "mcp>=1.28.1",
51
53
  "hvac>=2.0",
52
54
  "python-dotenv>=1.0",
@@ -61,6 +63,7 @@ dev = [
61
63
  "types-pyyaml>=6.0",
62
64
  "langchain-core>=0.3",
63
65
  "crewai>=0.80",
66
+ "agno>=3.0",
64
67
  "mcp>=1.28.1",
65
68
  "hvac>=2.0",
66
69
  "boto3>=1.34",
@@ -69,7 +72,7 @@ dev = [
69
72
 
70
73
  [project.urls]
71
74
  Homepage = "https://matimo.dev"
72
- Documentation = "https://matimo.dev/docs"
75
+ Documentation = "https://docs.matimo.dev/"
73
76
  Repository = "https://github.com/tallclub/matimo"
74
77
  Issues = "https://github.com/tallclub/matimo/issues"
75
78
 
@@ -80,7 +83,7 @@ core = "matimo:get_core_tools_path"
80
83
  packages = ["src/matimo"]
81
84
 
82
85
  [tool.hatch.build.targets.sdist]
83
- include = ["src/", "README.md", "../../../LICENSE"]
86
+ include = ["src/", "README.md", "LICENSE"]
84
87
 
85
88
  [tool.pytest.ini_options]
86
89
  testpaths = ["tests"]
@@ -34,6 +34,7 @@ from matimo.approval.handler import (
34
34
  ApprovalCallback,
35
35
  ApprovalHandler,
36
36
  ApprovalRequest,
37
+ definition_requires_approval,
37
38
  get_global_approval_handler,
38
39
  set_global_approval_handler,
39
40
  )
@@ -122,7 +123,7 @@ from matimo.errors import (
122
123
 
123
124
  # Executors
124
125
  from matimo.executors.command_executor import CommandExecutor
125
- from matimo.executors.function_executor import FunctionExecutor
126
+ from matimo.executors.function_executor import FunctionExecutor, FunctionToolContext
126
127
  from matimo.executors.http_executor import HttpExecutor
127
128
 
128
129
  # Main entry point + sync API
@@ -150,12 +151,26 @@ from matimo.mcp.tool_converter import convert_parameters_to_mcp_schema
150
151
 
151
152
  # Policy
152
153
  from matimo.policy.approval_manifest import ApprovalManifest, ApprovalRecord
154
+ from matimo.policy.audit_sink import (
155
+ AUDIT_GENESIS_HASH,
156
+ AuditLogVerification,
157
+ AuditSink,
158
+ JsonlFileSink,
159
+ hash_audit_entry,
160
+ redact_secrets,
161
+ verify_audit_log,
162
+ )
153
163
  from matimo.policy.content_validator import ContentViolation, validate_tool_content
154
164
  from matimo.policy.default_policy import DefaultPolicyEngine, PolicyEngine, get_tier_for_tool
155
165
  from matimo.policy.integrity_tracker import IntegrityAction, ToolIntegrityTracker
156
166
  from matimo.policy.policy_loader import load_policy_from_file
157
- from matimo.policy.risk_classifier import classify_risk
167
+ from matimo.policy.risk_classifier import (
168
+ classify_execution_risk,
169
+ classify_risk,
170
+ meets_risk_threshold,
171
+ )
158
172
  from matimo.policy.types import (
173
+ GovernanceMode,
159
174
  HITLCallback,
160
175
  HITLRequest,
161
176
  MatimoEvent,
@@ -170,7 +185,7 @@ from matimo.policy.types import (
170
185
  )
171
186
  from matimo.sync import MatimoSync
172
187
 
173
- __version__ = "0.1.0"
188
+ __version__ = "0.2.0"
174
189
 
175
190
 
176
191
  def get_core_tools_path() -> str:
@@ -231,6 +246,36 @@ def convert_tools_to_crewai(
231
246
  return _inner(tools, matimo_instance, credentials)
232
247
 
233
248
 
249
+ def convert_tools_to_agno(
250
+ tools: list[Any],
251
+ matimo_instance: Matimo,
252
+ credentials: dict[str, str] | None = None,
253
+ **kwargs: Any, # noqa: ANN401
254
+ ) -> list[Any]:
255
+ """Convert Matimo tools to Agno Function list. Requires agno.
256
+
257
+ Extra keyword arguments (context, confirm_risk_levels) are forwarded to
258
+ matimo.integrations.agno.convert_tools_to_agno.
259
+ """
260
+ from matimo.integrations.agno import convert_tools_to_agno as _inner
261
+ return _inner(tools, matimo_instance, credentials, **kwargs)
262
+
263
+
264
+ def MatimoTools( # noqa: N802
265
+ matimo_instance: Matimo,
266
+ tools: list[Any] | None = None,
267
+ **kwargs: Any, # noqa: ANN401
268
+ ) -> Any: # noqa: ANN401
269
+ """Build an Agno Toolkit exposing governed Matimo tools. Requires agno.
270
+
271
+ Named in CapWords to match Agno's <Name>Tools toolkit convention. Returns Any
272
+ because Toolkit comes from an optional dependency (agno). Extra keyword
273
+ arguments are forwarded to matimo.integrations.agno.MatimoTools.
274
+ """
275
+ from matimo.integrations.agno import MatimoTools as _inner
276
+ return _inner(matimo_instance, tools, **kwargs)
277
+
278
+
234
279
  # ---------------------------------------------------------------------------
235
280
  # Decorators
236
281
  # ---------------------------------------------------------------------------
@@ -272,7 +317,7 @@ __all__ = [
272
317
  "ParsedSkillContent", "SemanticSearchResult",
273
318
  "TfIdfEmbeddingProvider", "EmbeddingProvider", "cosine_similarity",
274
319
  # Executors
275
- "HttpExecutor", "CommandExecutor", "FunctionExecutor",
320
+ "HttpExecutor", "CommandExecutor", "FunctionExecutor", "FunctionToolContext",
276
321
  # Auth
277
322
  "inject_auth_parameters", "extract_parameter_placeholders",
278
323
  "OAuth2Handler", "OAuth2ProviderLoader",
@@ -280,17 +325,20 @@ __all__ = [
280
325
  # Approval
281
326
  "ApprovalHandler", "ApprovalRequest", "ApprovalCallback",
282
327
  "get_global_approval_handler", "set_global_approval_handler",
328
+ "definition_requires_approval",
283
329
  # Encodings
284
330
  "apply_parameter_encodings",
285
331
  # Policy
286
332
  "PolicyEngine", "DefaultPolicyEngine", "PolicyConfig",
287
333
  "PolicyDecision", "PolicyAllowed", "PolicyDenied", "PolicyPendingApproval",
288
334
  "RiskLevel", "PolicyTier",
289
- "MatimoEvent", "MatimoEventHandler", "HITLCallback", "HITLRequest",
335
+ "MatimoEvent", "MatimoEventHandler", "GovernanceMode", "HITLCallback", "HITLRequest",
290
336
  "ContentViolation", "validate_tool_content",
291
- "classify_risk", "get_tier_for_tool",
337
+ "classify_risk", "classify_execution_risk", "meets_risk_threshold", "get_tier_for_tool",
292
338
  "ToolIntegrityTracker", "IntegrityAction",
293
339
  "ApprovalManifest", "ApprovalRecord",
340
+ "AuditSink", "JsonlFileSink", "AuditLogVerification", "verify_audit_log",
341
+ "redact_secrets", "hash_audit_entry", "AUDIT_GENESIS_HASH",
294
342
  "load_policy_from_file",
295
343
  # MCP
296
344
  "MCPServer", "MCPServerOptions", "create_mcp_server",
@@ -303,6 +351,8 @@ __all__ = [
303
351
  "get_skills_metadata",
304
352
  "build_relevant_skill_prompt",
305
353
  "convert_tools_to_crewai",
354
+ "convert_tools_to_agno",
355
+ "MatimoTools",
306
356
  # Decorators
307
357
  "tool", "set_global_matimo_instance", "get_global_matimo_instance",
308
358
  # Logging
@@ -9,7 +9,11 @@ import logging
9
9
  import os
10
10
  from collections.abc import Awaitable, Callable
11
11
  from dataclasses import dataclass
12
- from typing import Any
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from matimo.core.models import ToolDefinition
16
+ from matimo.policy.types import GovernanceMode
13
17
 
14
18
  logger = logging.getLogger("matimo")
15
19
 
@@ -22,6 +26,32 @@ DEFAULT_DESTRUCTIVE_KEYWORDS: list[str] = [
22
26
  ]
23
27
 
24
28
 
29
+ # Tools whose approval prompt nothing may skip: neither MATIMO_AUTO_APPROVE nor
30
+ # an approved pattern (not even "*"). Approving a tool is the step that lets
31
+ # agent-written code run, so a human must always see it.
32
+ # Mirrors NEVER_PRE_APPROVED_TOOLS in approval-handler.ts.
33
+ NEVER_PRE_APPROVED_TOOLS: frozenset[str] = frozenset({"matimo_approve_tool"})
34
+
35
+
36
+ def definition_requires_approval(tool: ToolDefinition, mode: GovernanceMode = "secure") -> bool:
37
+ """
38
+ Whether a tool's definition alone makes every call need approval.
39
+ Mirrors definitionRequiresApproval() in approval-handler.ts: an explicit
40
+ `requires_approval` in the YAML always wins, so a developer can opt a tool
41
+ out with `requires_approval: false`. When it is absent, in "secure" mode
42
+ HTTP DELETE and `type: command` (shell) tools need approval by default;
43
+ "legacy" mode has no such default.
44
+ """
45
+ if "requires_approval" in tool.model_fields_set:
46
+ return tool.requires_approval
47
+ if mode == "legacy":
48
+ return False
49
+ execution = tool.execution
50
+ if execution.type == "command":
51
+ return True
52
+ return execution.type == "http" and execution.method.upper() == "DELETE"
53
+
54
+
25
55
  @dataclass
26
56
  class ApprovalRequest:
27
57
  """Represents a pending approval for a tool execution."""
@@ -58,33 +88,59 @@ class ApprovalHandler:
58
88
  # Public API
59
89
  # ------------------------------------------------------------------
60
90
 
61
- def set_approval_callback(self, callback: ApprovalCallback) -> None:
62
- """Wire an async approval callback (e.g., Slack DM, CLI prompt)."""
91
+ def set_approval_callback(self, callback: ApprovalCallback | None) -> None:
92
+ """Wire an async approval callback (e.g., Slack DM, CLI prompt), or clear it."""
63
93
  self._callback = callback
64
94
 
65
- async def request_approval(self, request: ApprovalRequest) -> bool:
95
+ def get_approval_callback(self) -> ApprovalCallback | None:
96
+ """Return the current approval callback (for save/restore patterns)."""
97
+ return self._callback
98
+
99
+ def requires_approval(
100
+ self, requires_approval_in_yaml: bool | None, content: str | None = None
101
+ ) -> bool:
66
102
  """
67
- Gate execution on approval.
68
- Returns True if approved, False if denied.
103
+ Whether a call needs per-call approval. Mirrors requiresApproval() in
104
+ approval-handler.ts: an explicit YAML `requires_approval: true` always
105
+ does; otherwise the supplied content (SQL, shell command, ...) is
106
+ scanned for destructive keywords.
69
107
  """
70
- # 1. Hard auto-approve (CI / testing)
71
- if self.auto_approve:
72
- logger.debug(
73
- "Auto-approving tool '%s' (MATIMO_AUTO_APPROVE=true)", request.tool_name
74
- )
108
+ if requires_approval_in_yaml is True:
75
109
  return True
110
+ if content:
111
+ upper = content.upper()
112
+ return any(kw in upper for kw in self.destructive_keywords)
113
+ return False
114
+
115
+ def is_pre_approved(self, tool_name: str) -> bool:
116
+ """True when MATIMO_AUTO_APPROVE is on or the tool matches an approved pattern.
117
+ Never for NEVER_PRE_APPROVED_TOOLS."""
118
+ if tool_name in NEVER_PRE_APPROVED_TOOLS:
119
+ return False
120
+ return self.auto_approve or self._matches_approved_pattern(tool_name)
76
121
 
77
- # 2. Pattern allowlist
78
- if self._matches_approved_pattern(request.tool_name):
122
+ async def request_approval(
123
+ self, request: ApprovalRequest, callback: ApprovalCallback | None = None
124
+ ) -> bool:
125
+ """
126
+ Gate execution on approval.
127
+ Returns True if approved, False if denied.
128
+ `callback` overrides this handler's callback for this request (a Matimo
129
+ instance passes its own `on_approval` here).
130
+ """
131
+ callback = callback if callback is not None else self._callback
132
+ # 1-2. MATIMO_AUTO_APPROVE (CI / testing) or an approved pattern —
133
+ # never for NEVER_PRE_APPROVED_TOOLS
134
+ if self.is_pre_approved(request.tool_name):
79
135
  logger.debug(
80
- "Tool '%s' matches approved pattern — skipping approval prompt",
136
+ "Tool '%s' is pre-approved (MATIMO_AUTO_APPROVE or approved pattern)",
81
137
  request.tool_name,
82
138
  )
83
139
  return True
84
140
 
85
141
  # 3. HITL callback
86
- if self._callback is not None:
87
- approved = await self._callback(request)
142
+ if callback is not None:
143
+ approved = await callback(request)
88
144
  if not approved:
89
145
  logger.info(
90
146
  "Approval denied for tool '%s' by callback", request.tool_name
@@ -125,8 +181,9 @@ class ApprovalHandler:
125
181
  return {p.strip() for p in raw.split(",") if p.strip()}
126
182
 
127
183
  def _matches_approved_pattern(self, tool_name: str) -> bool:
184
+ # Case-insensitive on every OS, like matchesPattern() in approval-handler.ts
128
185
  return any(
129
- fnmatch.fnmatch(tool_name, pattern)
186
+ fnmatch.fnmatchcase(tool_name.lower(), pattern.lower())
130
187
  for pattern in self.approved_patterns
131
188
  )
132
189
 
@@ -31,8 +31,8 @@ def inject_auth_parameters(
31
31
  Scan all placeholders in the tool's execution config (URL, headers, body,
32
32
  query_params). For any placeholder that looks auth-related and has no value
33
33
  in params, attempt to resolve it from:
34
- 1. per-call credentials dict
35
- 2. process environment (MATIMO_{TOOL_NAME}_{KEY} or just {KEY})
34
+ 1. per-call credentials dict ({KEY}, then MATIMO_{KEY})
35
+ 2. process environment (MATIMO_{KEY}, MATIMO_{TOOL_NAME}_{KEY}, then {KEY})
36
36
 
37
37
  SECURITY: injected values are never logged.
38
38
 
@@ -71,21 +71,20 @@ def extract_parameter_placeholders(tool: ToolDefinition) -> set[str]:
71
71
  """
72
72
  placeholders: set[str] = set()
73
73
  exec_cfg = tool.execution
74
- exec_type = exec_cfg.type
75
-
76
- if exec_type == "http":
77
- _scan_string(exec_cfg.url, placeholders) # type: ignore[attr-defined]
78
- _scan_object(exec_cfg.headers, placeholders) # type: ignore[attr-defined]
79
- _scan_object(exec_cfg.body, placeholders) # type: ignore[attr-defined]
80
- _scan_object(exec_cfg.query_params, placeholders) # type: ignore[attr-defined]
81
- _scan_object(exec_cfg.params, placeholders) # type: ignore[attr-defined]
82
-
83
- elif exec_type == "command":
84
- _scan_string(exec_cfg.command, placeholders) # type: ignore[attr-defined]
85
- for arg in exec_cfg.args or []: # type: ignore[attr-defined]
74
+
75
+ if exec_cfg.type == "http":
76
+ _scan_string(exec_cfg.url, placeholders)
77
+ _scan_object(exec_cfg.headers, placeholders)
78
+ _scan_object(exec_cfg.body, placeholders)
79
+ _scan_object(exec_cfg.query_params, placeholders)
80
+ _scan_object(exec_cfg.params, placeholders)
81
+
82
+ elif exec_cfg.type == "command":
83
+ _scan_string(exec_cfg.command, placeholders)
84
+ for arg in exec_cfg.args or []:
86
85
  _scan_string(arg, placeholders)
87
86
 
88
- elif exec_type == "function":
87
+ elif exec_cfg.type == "function":
89
88
  # Function tools may have params passed directly — nothing to scan
90
89
  pass
91
90
 
@@ -103,19 +102,27 @@ def _resolve_auth_value(
103
102
  credentials: dict[str, str] | None,
104
103
  ) -> str | None:
105
104
  """
106
- Try to resolve an auth placeholder in priority order:
107
- 1. per-call credentials
108
- 2. env MATIMO_{TOOL_NAME_UPPER}_{PLACEHOLDER_UPPER}
109
- 3. env {PLACEHOLDER} directly
105
+ Try to resolve an auth placeholder in priority order, matching
106
+ injectAuthParameters() in matimo-instance.ts:
107
+ 1. per-call credentials: {PLACEHOLDER}, then MATIMO_{PLACEHOLDER}
108
+ 2. env MATIMO_{PLACEHOLDER}
109
+ 3. env MATIMO_{TOOL_NAME_UPPER}_{PLACEHOLDER_UPPER} (Python-only, kept for
110
+ existing deployments)
111
+ 4. env {PLACEHOLDER}
110
112
  """
111
- if credentials and placeholder in credentials:
112
- return credentials[placeholder]
113
-
114
- # e.g. MATIMO_SLACK_SLACK_BOT_TOKEN
115
- env_key_prefixed = f"MATIMO_{tool_name.upper()}_{placeholder.upper()}"
116
- val = os.environ.get(env_key_prefixed)
117
- if val:
118
- return val
113
+ if credentials:
114
+ for key in (placeholder, f"MATIMO_{placeholder}"):
115
+ if credentials.get(key):
116
+ return credentials[key]
117
+
118
+ for env_key in (
119
+ f"MATIMO_{placeholder}",
120
+ # e.g. MATIMO_SLACK_SEND_CHANNEL_MESSAGE_SLACK_BOT_TOKEN
121
+ f"MATIMO_{tool_name.upper()}_{placeholder.upper()}",
122
+ ):
123
+ val = os.environ.get(env_key)
124
+ if val:
125
+ return val
119
126
 
120
127
  # env directly (e.g. SLACK_BOT_TOKEN)
121
128
  return os.environ.get(placeholder)