griot-rag 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 (127) hide show
  1. griot_rag-0.2.0/LICENSE +190 -0
  2. griot_rag-0.2.0/PKG-INFO +295 -0
  3. griot_rag-0.2.0/README.md +250 -0
  4. griot_rag-0.2.0/pyproject.toml +119 -0
  5. griot_rag-0.2.0/setup.cfg +4 -0
  6. griot_rag-0.2.0/src/griot/__init__.py +42 -0
  7. griot_rag-0.2.0/src/griot/ask.py +79 -0
  8. griot_rag-0.2.0/src/griot/auth.py +287 -0
  9. griot_rag-0.2.0/src/griot/cli.py +699 -0
  10. griot_rag-0.2.0/src/griot/common.py +3355 -0
  11. griot_rag-0.2.0/src/griot/config.py +600 -0
  12. griot_rag-0.2.0/src/griot/doctor.py +400 -0
  13. griot_rag-0.2.0/src/griot/freshness.py +210 -0
  14. griot_rag-0.2.0/src/griot/golden_set.py +421 -0
  15. griot_rag-0.2.0/src/griot/harnesses.py +1232 -0
  16. griot_rag-0.2.0/src/griot/index_branches.py +268 -0
  17. griot_rag-0.2.0/src/griot/index_code.py +304 -0
  18. griot_rag-0.2.0/src/griot/index_commits.py +169 -0
  19. griot_rag-0.2.0/src/griot/index_platform.py +212 -0
  20. griot_rag-0.2.0/src/griot/index_tags.py +190 -0
  21. griot_rag-0.2.0/src/griot/jobs.py +520 -0
  22. griot_rag-0.2.0/src/griot/logdb.py +580 -0
  23. griot_rag-0.2.0/src/griot/mcp_server.py +2473 -0
  24. griot_rag-0.2.0/src/griot/platforms.py +702 -0
  25. griot_rag-0.2.0/src/griot/quality_check.py +331 -0
  26. griot_rag-0.2.0/src/griot/redaction.py +338 -0
  27. griot_rag-0.2.0/src/griot/repos.py +202 -0
  28. griot_rag-0.2.0/src/griot/resources/agents/claude-code/griot-setup-assistant.md +134 -0
  29. griot_rag-0.2.0/src/griot/resources/agents/opencode/griot-setup-assistant.md +135 -0
  30. griot_rag-0.2.0/src/griot/resources/instructions/claude-code.md +3 -0
  31. griot_rag-0.2.0/src/griot/resources/skills/griot-indexing/SKILL.md +195 -0
  32. griot_rag-0.2.0/src/griot/resources/skills/griot-onboarding/SKILL.md +158 -0
  33. griot_rag-0.2.0/src/griot/resources/skills/griot-operations/SKILL.md +216 -0
  34. griot_rag-0.2.0/src/griot/resources/skills/griot-troubleshooting/SKILL.md +167 -0
  35. griot_rag-0.2.0/src/griot/resources/skills/griot-workflows/SKILL.md +144 -0
  36. griot_rag-0.2.0/src/griot/retrieval_eval.py +230 -0
  37. griot_rag-0.2.0/src/griot/stats.py +827 -0
  38. griot_rag-0.2.0/src/griot_rag.egg-info/PKG-INFO +295 -0
  39. griot_rag-0.2.0/src/griot_rag.egg-info/SOURCES.txt +125 -0
  40. griot_rag-0.2.0/src/griot_rag.egg-info/dependency_links.txt +1 -0
  41. griot_rag-0.2.0/src/griot_rag.egg-info/entry_points.txt +2 -0
  42. griot_rag-0.2.0/src/griot_rag.egg-info/requires.txt +21 -0
  43. griot_rag-0.2.0/src/griot_rag.egg-info/top_level.txt +1 -0
  44. griot_rag-0.2.0/tests/test_ask.py +135 -0
  45. griot_rag-0.2.0/tests/test_audit_history.py +465 -0
  46. griot_rag-0.2.0/tests/test_audit_tool.py +323 -0
  47. griot_rag-0.2.0/tests/test_auth.py +361 -0
  48. griot_rag-0.2.0/tests/test_batch_sizes.py +243 -0
  49. griot_rag-0.2.0/tests/test_branches_few_git_calls.py +437 -0
  50. griot_rag-0.2.0/tests/test_bundled_skills.py +36 -0
  51. griot_rag-0.2.0/tests/test_chat_profiles.py +175 -0
  52. griot_rag-0.2.0/tests/test_chunk_text.py +63 -0
  53. griot_rag-0.2.0/tests/test_claude_config_dir.py +285 -0
  54. griot_rag-0.2.0/tests/test_cli.py +591 -0
  55. griot_rag-0.2.0/tests/test_cli_confirm.py +281 -0
  56. griot_rag-0.2.0/tests/test_cli_hints.py +139 -0
  57. griot_rag-0.2.0/tests/test_cli_search_filters.py +150 -0
  58. griot_rag-0.2.0/tests/test_client_release_race.py +252 -0
  59. griot_rag-0.2.0/tests/test_config_command.py +568 -0
  60. griot_rag-0.2.0/tests/test_config_dirs.py +219 -0
  61. griot_rag-0.2.0/tests/test_config_tool.py +288 -0
  62. griot_rag-0.2.0/tests/test_confirmation.py +359 -0
  63. griot_rag-0.2.0/tests/test_confirmation_copy.py +155 -0
  64. griot_rag-0.2.0/tests/test_correctness_fixes.py +451 -0
  65. griot_rag-0.2.0/tests/test_discovery_rules.py +311 -0
  66. griot_rag-0.2.0/tests/test_doctor.py +518 -0
  67. griot_rag-0.2.0/tests/test_embed_batching.py +115 -0
  68. griot_rag-0.2.0/tests/test_env_template.py +217 -0
  69. griot_rag-0.2.0/tests/test_gemini_direct.py +149 -0
  70. griot_rag-0.2.0/tests/test_git_control_characters.py +159 -0
  71. griot_rag-0.2.0/tests/test_git_hardening.py +234 -0
  72. griot_rag-0.2.0/tests/test_git_hooks.py +378 -0
  73. griot_rag-0.2.0/tests/test_git_hooks_every_route.py +947 -0
  74. griot_rag-0.2.0/tests/test_golden_set.py +400 -0
  75. griot_rag-0.2.0/tests/test_golden_set_suggest.py +238 -0
  76. griot_rag-0.2.0/tests/test_golden_set_suggest_tool.py +324 -0
  77. griot_rag-0.2.0/tests/test_harnesses.py +668 -0
  78. griot_rag-0.2.0/tests/test_http_connection_reuse.py +310 -0
  79. griot_rag-0.2.0/tests/test_index_branches.py +165 -0
  80. griot_rag-0.2.0/tests/test_index_commits.py +142 -0
  81. griot_rag-0.2.0/tests/test_index_platform.py +106 -0
  82. griot_rag-0.2.0/tests/test_index_preview.py +312 -0
  83. griot_rag-0.2.0/tests/test_index_status.py +359 -0
  84. griot_rag-0.2.0/tests/test_index_tags.py +136 -0
  85. griot_rag-0.2.0/tests/test_indexer_discover.py +113 -0
  86. griot_rag-0.2.0/tests/test_indexing.py +838 -0
  87. griot_rag-0.2.0/tests/test_install_flow.py +490 -0
  88. griot_rag-0.2.0/tests/test_jobs.py +464 -0
  89. griot_rag-0.2.0/tests/test_keychain.py +238 -0
  90. griot_rag-0.2.0/tests/test_lazy_embedding_import.py +50 -0
  91. griot_rag-0.2.0/tests/test_lock.py +123 -0
  92. griot_rag-0.2.0/tests/test_logdb.py +551 -0
  93. griot_rag-0.2.0/tests/test_mcp_environment_only_narrows.py +602 -0
  94. griot_rag-0.2.0/tests/test_mcp_output_types_on_the_oldest_python.py +101 -0
  95. griot_rag-0.2.0/tests/test_mcp_registration.py +396 -0
  96. griot_rag-0.2.0/tests/test_mcp_server.py +2498 -0
  97. griot_rag-0.2.0/tests/test_openai_compatible.py +145 -0
  98. griot_rag-0.2.0/tests/test_orphans.py +602 -0
  99. griot_rag-0.2.0/tests/test_platform_hardening.py +278 -0
  100. griot_rag-0.2.0/tests/test_platforms.py +411 -0
  101. griot_rag-0.2.0/tests/test_private_directories.py +192 -0
  102. griot_rag-0.2.0/tests/test_profiles.py +312 -0
  103. griot_rag-0.2.0/tests/test_profiles_use.py +265 -0
  104. griot_rag-0.2.0/tests/test_project_name.py +300 -0
  105. griot_rag-0.2.0/tests/test_quality_check.py +359 -0
  106. griot_rag-0.2.0/tests/test_quality_check_golden_set.py +363 -0
  107. griot_rag-0.2.0/tests/test_redaction.py +357 -0
  108. griot_rag-0.2.0/tests/test_redaction_wiring.py +444 -0
  109. griot_rag-0.2.0/tests/test_release.py +176 -0
  110. griot_rag-0.2.0/tests/test_repos.py +321 -0
  111. griot_rag-0.2.0/tests/test_repository_freshness.py +631 -0
  112. griot_rag-0.2.0/tests/test_retrieval_eval.py +278 -0
  113. griot_rag-0.2.0/tests/test_search_filters.py +269 -0
  114. griot_rag-0.2.0/tests/test_search_grouping.py +120 -0
  115. griot_rag-0.2.0/tests/test_search_results.py +294 -0
  116. griot_rag-0.2.0/tests/test_secret_leaks.py +105 -0
  117. griot_rag-0.2.0/tests/test_secure_files.py +167 -0
  118. griot_rag-0.2.0/tests/test_security_hardening.py +442 -0
  119. griot_rag-0.2.0/tests/test_server_instructions.py +136 -0
  120. griot_rag-0.2.0/tests/test_spend_circuit_breaker.py +134 -0
  121. griot_rag-0.2.0/tests/test_spend_without_usage.py +232 -0
  122. griot_rag-0.2.0/tests/test_stable_id.py +18 -0
  123. griot_rag-0.2.0/tests/test_stats.py +881 -0
  124. griot_rag-0.2.0/tests/test_stats_state.py +457 -0
  125. griot_rag-0.2.0/tests/test_supply_chain.py +248 -0
  126. griot_rag-0.2.0/tests/test_tag_chunks_and_hash.py +311 -0
  127. griot_rag-0.2.0/tests/test_tool_approval.py +565 -0
@@ -0,0 +1,190 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ Copyright 2026 johnt1000
179
+
180
+ Licensed under the Apache License, Version 2.0 (the "License");
181
+ you may not use this file except in compliance with the License.
182
+ You may obtain a copy of the License at
183
+
184
+ http://www.apache.org/licenses/LICENSE-2.0
185
+
186
+ Unless required by applicable law or agreed to in writing, software
187
+ distributed under the License is distributed on an "AS IS" BASIS,
188
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
189
+ See the License for the specific language governing permissions and
190
+ limitations under the License.
@@ -0,0 +1,295 @@
1
+ Metadata-Version: 2.4
2
+ Name: griot-rag
3
+ Version: 0.2.0
4
+ Summary: Local-first RAG over your git repositories — index code, git history and platform data (PRs/issues/releases) into an embedded vector store, search it and ask questions from the CLI or via MCP
5
+ Author: johnt1000
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Homepage, https://github.com/johnt1000/griot
8
+ Project-URL: Repository, https://github.com/johnt1000/griot
9
+ Project-URL: Issues, https://github.com/johnt1000/griot/issues
10
+ Project-URL: Changelog, https://github.com/johnt1000/griot/blob/main/CHANGELOG.md
11
+ Keywords: rag,vector-search,git,mcp,mcp-server,claude-code,code-search,semantic-search,local-first,developer-tools,qdrant,embeddings
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Software Development :: Version Control :: Git
23
+ Classifier: Topic :: Text Processing :: Indexing
24
+ Requires-Python: >=3.10
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: requests
28
+ Requires-Dist: tqdm
29
+ Requires-Dist: python-dotenv
30
+ Requires-Dist: qdrant-client[fastembed]
31
+ Requires-Dist: psutil
32
+ Requires-Dist: qdrant-edge-py<0.9,>=0.8.0
33
+ Requires-Dist: mcp<3,>=2.0.0
34
+ Requires-Dist: typing-extensions>=4.6
35
+ Requires-Dist: pydantic>=2
36
+ Requires-Dist: anyio
37
+ Provides-Extra: dev
38
+ Requires-Dist: pytest; extra == "dev"
39
+ Requires-Dist: packaging; extra == "dev"
40
+ Requires-Dist: pyyaml; extra == "dev"
41
+ Requires-Dist: tomli; python_version < "3.11" and extra == "dev"
42
+ Provides-Extra: keychain
43
+ Requires-Dist: keyring>=24; extra == "keychain"
44
+ Dynamic: license-file
45
+
46
+ # griot
47
+
48
+ [![CI](https://github.com/johnt1000/griot/actions/workflows/ci.yml/badge.svg)](https://github.com/johnt1000/griot/actions/workflows/ci.yml)
49
+
50
+ Local-first RAG over your git repositories. griot indexes source code, git history (commits, tags, branches) and code-platform data (PRs/MRs, releases, issues) into an **embedded** vector store — no database server, no Docker — and lets you search it or ask questions about it, from the CLI or from an AI agent via [MCP](https://modelcontextprotocol.io/).
51
+
52
+ Named after the West African storyteller who keeps a community's history: griot remembers what your repositories have been through.
53
+
54
+ ## Highlights
55
+
56
+ - **Fully local storage** — vectors live in an in-process [Qdrant Edge](https://qdrant.tech/edge/) shard under your XDG data dir. No services to run.
57
+ - **Free by default** — the default embedding profile (`jina-code`) runs locally via ONNX. Paid profiles (OpenAI, Gemini) are opt-in.
58
+ - **Spend circuit breaker** — daily ceiling + 5-minute velocity ceiling on every paid call, with atomic on-disk state. The `openai` and `deepseek` chat profiles refuse to run until you set their price (`griot config set openai-chat-price <USD per 1M tokens>`, or `deepseek-chat-price`), so the breaker always tracks real cost.
59
+ - **Five platforms** — GitHub, GitLab (incl. self-hosted), Bitbucket Cloud, Azure DevOps and Gitea/Forgejo adapters for PRs/releases/issues, detected from each repo's `origin` remote. These are built against each provider's documented API and covered by tests with mocked HTTP; only the GitHub path has been exercised against a live account.
60
+ - **MCP server** — expose search/status/quality tools to Claude Code, opencode or any MCP client. Indexing via agent is off by default and path-allowlisted.
61
+ - **Security-hardened** — API keys never in URLs or logs, 0600/0700 file modes on everything it writes, no credential ever follows a redirect. See [SECURITY.md](SECURITY.md).
62
+
63
+ **Status:** v0.2.0, beta. One maintainer, used daily by its author. The CLI surface and the on-disk layout may still change between 0.x releases.
64
+
65
+ ## Installation
66
+
67
+ ```bash
68
+ pipx install griot-rag # the distribution is griot-rag; the command is griot
69
+ ```
70
+
71
+ Or from a checkout: `git clone https://github.com/johnt1000/griot && cd griot && pipx install .` (`pipx install -e .` for an editable install).
72
+
73
+ Requires Python ≥ 3.10 and `git`. **The first run of a local profile downloads its ONNX model from Hugging Face** (~1.1 GB for the default `jina-code`) and caches it under your data directory; `griot profiles list` shows each profile's RAM tier against the RAM you actually have. CI runs the suite on 3.10 and 3.13, scans for committed secrets, and installs the built wheel in a clean environment on every push.
74
+
75
+ ## Quickstart
76
+
77
+ ```bash
78
+ # 1. register the repos you want to index (asks you to confirm, in a terminal)
79
+ griot repos add ~/code/my-app
80
+ griot repos add ~/code/my-lib
81
+
82
+ # 2. see what would be indexed (never spends anything)
83
+ griot index all --repo my-app --dry-run
84
+
85
+ # 3. index for real (default profile is local & free)
86
+ griot index all --repo my-app
87
+
88
+ # 4. search (vector search only — free, no LLM)
89
+ griot search "where is the retry logic for the payment API?"
90
+
91
+ # 5. ask (search + LLM synthesis — requires a chat provider, see below)
92
+ griot ask "how does authentication work in this codebase?" --show-sources
93
+
94
+ # 6. keep an eye on usage and spend
95
+ griot stats
96
+
97
+ # 7. when something does not work: every check at once, reads only
98
+ griot doctor
99
+ ```
100
+
101
+ `griot doctor` checks the whole setup in one go and says what to do about each finding. It changes no setting, index or file of yours; two things happen on the way and are said: loading the configuration closes a `.env` left open to other users, as every griot command does, and asking the harness which server it has registered may start that server for a moment, as `griot assist install` does. It checks settings the file holds that griot cannot start with, the configuration file and directories closed to other users, the active profile and its credential, the collection, the registered repositories and whether their index is behind, today's spend against the ceiling, the MCP registration and which read-only tools still ask before every call, the variables a server would ignore, git, the log. Exit status 1 only when a check fails; a warning is something to know.
102
+
103
+ `griot index all` runs the sources in order: `code`, `commits`, `tags`, `branches`, `platform`. Filter with `--sources code,commits`. Index an unregistered directory directly with `--path <dir>`.
104
+
105
+ In a git work tree `index code` reads what git does not ignore (tracked files and new ones), skips symlinks and files over 1 MB, and replaces credential-looking values before anything is embedded. After each run the points whose source is gone are removed: a deleted file, a deleted branch. That removal is held back when more than half of a repository would go (`--prune` overrides) and never happens for a `--path` run, so register a repository you index regularly. `--dry-run` says what a run would embed and remove, at no cost.
106
+
107
+ ## Embedding profiles
108
+
109
+ Each profile gets its own collection (vectors from different models aren't comparable). Make one the active profile with `griot profiles use <name>`, which writes `GRIOT_EMBED_PROFILE` to `<config>/.env` (it asks first when the profile calls an API; `--yes` answers), or pick one for a single run with `--profile`. A profile switched to has its own, empty index until you run `griot index all`, and an MCP server that is already running keeps the profile it started with. A `GRIOT_EMBED_PROFILE` exported in the environment, or set in a server's own `env`, wins over the file.
110
+
111
+ | Profile | Backend | Cost | Notes |
112
+ |---|---|---|---|
113
+ | `jina-code` (default) | local ONNX | free | code-specialist, 768-dim |
114
+ | `bge-small`, `nomic-q`, `mxbai-large`, `bge-m3`, `bge-large-en` | local ONNX | free | RAM-tiered alternatives — `griot profiles list` shows what fits your machine |
115
+ | `openai-small` | OpenAI API | paid | needs `GRIOT_OPENAI_API_KEY` |
116
+ | `gemini` | Gemini API | paid | needs `GEMINI_TOKEN` |
117
+
118
+ `griot profiles list` shows every profile with RAM estimates and credential status. `griot profiles delete <profile>` permanently deletes that profile's on-disk collection to reclaim disk space (refuses the active profile, and refuses while any indexing run is in progress). It asks for confirmation at an interactive terminal and has no `--yes`.
119
+
120
+ ## Chat profiles (`griot ask` only)
121
+
122
+ Search is controlled by the *embedding* profile above; the chat profile only decides which LLM writes the final answer. Select with `GRIOT_CHAT_PROFILE` or `--chat-profile`.
123
+
124
+ | Profile | Credential | Default model | Price config |
125
+ |---|---|---|---|
126
+ | `gemini` (default) | `GEMINI_TOKEN` | gemini flash | built-in |
127
+ | `openai` | `GRIOT_OPENAI_API_KEY` | gpt mini tier | **required**: `GRIOT_OPENAI_CHAT_PRICE_PER_1M_TOKENS` |
128
+ | `deepseek` | `GRIOT_DEEPSEEK_API_KEY` | deepseek-chat | **required**: `GRIOT_DEEPSEEK_CHAT_PRICE_PER_1M_TOKENS` |
129
+ | `groq` | `GRIOT_GROQ_API_KEY` | llama-3.3-70b-versatile | defaults to $0 (free tier — verify current limits in Groq's console) |
130
+
131
+ griot never assumes an unverified price: `openai`/`deepseek` refuse to run until you set their price (`griot config set openai-chat-price <USD per 1M tokens>`, or `deepseek-chat-price`), so the spend circuit breaker always tracks real cost.
132
+
133
+ ## Credentials
134
+
135
+ ```bash
136
+ griot auth set openai # hidden input; OS keychain when available, else <config>/.env at 0600
137
+ griot auth list # status per provider, keys always masked
138
+ griot auth remove openai # asks first; --yes skips the question
139
+ griot auth migrate # moves every credential already in the plaintext file into the keychain
140
+ ```
141
+
142
+ Install the optional `keychain` extra (`pip install "griot[keychain]"`) and credentials go to the OS keychain — macOS Keychain, Linux Secret Service, Windows Credential Manager — instead of the plaintext file. Without it, or where no backend is reachable, griot falls back to `<config>/.env` at mode 0600. A credential set before the extra was installed stays in the file until you run `griot auth migrate` (or re-run `griot auth set` for that one provider).
143
+
144
+ Platform tokens (only needed for `griot index platform`): `GITHUB_TOKEN`, `GITLAB_PERSONAL_ACCESS_TOKEN`, `BITBUCKET_ACCESS_TOKEN`, `AZURE_DEVOPS_PAT`, `GITEA_TOKEN`.
145
+
146
+ The first time you run any `griot` command, `<config>/.env` is generated for you with every setting listed, mode 0600: most with their default written out, those whose default may still change commented out, and credentials empty. You rarely need to open it: `griot config list` shows each setting, the value in force and where it comes from, and `griot config set` changes one.
147
+
148
+ ## MCP server
149
+
150
+ The server has to be registered with your agent before its tools exist in a session. The installer can do it for you:
151
+
152
+ ```bash
153
+ griot assist install # for every project: copies the skills, then asks about the rest
154
+ griot assist install --scope local # for this project only
155
+ ```
156
+
157
+ It first asks the harness what is registered already. A server that runs this griot is left alone, and so is one that runs anything else that is still there. One whose command no longer exists is offered to be replaced, showing the two commands it would run (remove, then add), and only at the scope being installed: an install for one project never removes what is registered for every project, and an install for every project never touches a project's own registration (it says so when that one is broken, since it takes precedence there). Otherwise it shows the exact command and runs it only after you type `y` (`--mcp` answers yes and makes the command fail if the registration does, `--no-mcp` skips the question). For Claude Code that command is `claude mcp add --scope user griot -- <path to griot> mcp`, and the way back is `claude mcp remove --scope user griot` (`--scope local` for a per-project registration); the installer prints it. Install griot as a tool first (`pipx` or `uv tool`): what gets registered is the path of the griot you ran, and one inside a project's virtual environment stops working when that environment goes.
158
+
159
+ The installer then **offers** to let the agent call griot's read-only tools without asking each time: an agent that has to ask before every search mostly does not search. For Claude Code it shows the rules (`mcp__griot__griot_search` and the other read-only tools, as the server itself marks them) and the file, and adds them to `permissions.allow` only after you type `y`: in `~/.claude/settings.json` with `--scope global`, otherwise in the project's personal `.claude/settings.local.json`. (Wherever this page says `~/.claude`, read the directory `CLAUDE_CONFIG_DIR` names when you have set it: Claude Code keeps its user files there, and the installer follows it for the skills, the agent, the instructions block and these rules.) Every other setting keeps its value (the file is written back as indented JSON, so its layout may change), a rule or pattern you already have under `deny` or `ask` wins and is left out, and a file griot cannot edit safely is not touched: not plain JSON settings, a key given twice, read-only. griot adds no rule for the tools that change anything, nor for the quality check. A rule matches any MCP server named `griot`, whoever defines it. There is no flag that answers yes, an MCP tool never does this, and `--no-allow-tools` skips the question. To undo, remove the rules from that file.
160
+
161
+ Registered for every project, each open session starts its own griot server. With a paid embedding profile that is light. With a local one each server loads the model on its first search, from about 100 MB to a few GB depending on the profile (`griot profiles list` shows each profile's estimate). What may be indexed does not change with where the server is registered: that is decided by `repos.json` and `GRIOT_MCP_INDEX_ROOTS`.
162
+
163
+ To register it yourself, per project:
164
+
165
+ ```bash
166
+ claude mcp add --transport stdio griot --scope project -- griot mcp
167
+ ```
168
+
169
+ or in `.mcp.json`:
170
+
171
+ ```json
172
+ {
173
+ "mcpServers": {
174
+ "griot": {
175
+ "command": "griot",
176
+ "args": ["mcp"]
177
+ }
178
+ }
179
+ }
180
+ ```
181
+
182
+ Leave `env` out unless you want this project to differ from your own configuration. A variable set there wins over `griot config` for that server only where it narrows what your configuration says: one that would turn on indexing through MCP, add a directory an agent may index, raise a spend ceiling, send a platform token to another host, switch to a profile that calls an API or let an index run fail for longer is ignored (the server says so on stderr and in `griot_config_list`). Those are set with `griot config set` and `griot profiles use`, or, for a profile, with `--profile` in the server's `args`. `GRIOT_PROJECT` is the one that belongs in `env`. A server also refuses to start with its configuration or data directory inside the project it was started in.
183
+
184
+ The server sends instructions when it connects: what griot covers, when to search it first and when to read or grep instead. A client that passes server instructions on to the agent (Claude Code does) needs nothing installed for that.
185
+
186
+ `griot_search` takes an optional `group_by_document`: off by default (up to three chunks of one document, so it can answer in some depth without taking every slot), on when you want breadth (the best chunk of each document, so the same number of results reaches more files, commits and PRs). `repos` and `source_types` narrow a search to some repositories and to some kinds of source (`code`, `commit`, `tag`, `branch`, `merge_request`, `release`, `issue`); a repository with nothing indexed, or a kind that does not exist, is an error rather than an empty result. `griot search` takes the same as `--repo`, `--source-type` and `--group-by-document`. Each indexing run records what every repository looked like (its HEAD, and the tag and remote-branch refs), so `griot_index_status` says, per registered repository, whether its index is behind the repository and how: commits made since the code and commits sources ran (or that the indexed commit is no longer in the history: rewritten, or another branch checked out), whether the tags or remote branches changed (the base branch counts, since each branch is described against it), and which sources never ran; `griot_search` names the repositories among its results that are behind (`behind`), and `griot stats` lists them under attention. Pull requests and issues live on the platform, so nothing local can say whether that source is behind.
187
+
188
+ The server's own tool list is the inventory (your client shows it), and [docs/mcp-capability-coverage.md](docs/mcp-capability-coverage.md) maps each tool to its CLI command. The read-only ones cover search, index and spend status, the usage report, the lists of repositories, profiles and curated cases, the settings the server is running with, and which credentials are configured. Four more read without changing anything and still ask each time, because they cost or read far more than a search does: the quality check (the self-check and the curated golden set), a preview of what an index run would embed and remove (`griot_index_preview`: free, and available whether or not indexing through MCP is enabled), an audit of where the index holds credential-looking values, and candidate golden-set cases from a repository's git log.
189
+
190
+ Four prompts, which clients surface as slash commands:
191
+
192
+ | Command | What it does |
193
+ |---|---|
194
+ | `/mcp__griot__stats` | The same usage report `griot stats` prints, read for you. |
195
+ | `/mcp__griot__history` | Investigates a question across every source type — code, commits, PRs, issues — and answers as a cited history, oldest cause first. |
196
+ | `/mcp__griot__health` | Says whether the index is worth trusting, and which kind of failure it is if not. |
197
+ | `/mcp__griot__overview` | What is indexed here, and which registered repos are no longer usable. |
198
+
199
+ A prompt injects text; the work is still a tool call, so nothing here runs in the background or spends anything on its own.
200
+
201
+ The tools that change something register or remove a repository, delete a profile, curate the golden set, install the skills (`griot_assist_install`, below) and index a repository (`griot_index_repo`, **off by default** — it can spend money on paid profiles; you enable it with `griot config set mcp-index true`, which asks at a terminal, and even then it only accepts paths registered via `griot repos add` or under `GRIOT_MCP_INDEX_ROOTS`). None of them act unasked. Where your client can show a confirmation dialog they ask you, and only your answer counts: a `confirm=true` argument from the agent is ignored there, and a "no" is final. Where the client cannot ask, they refuse and hand back the equivalent `griot` command, and an explicit `confirm=true` argument re-runs them — which means that on such a client an agent that passes `confirm=true` up front executes without a human. That fallback is deliberate: it is the only thing that works on a client that cannot prompt. **Registering a new repo, deleting a profile, and installing assist skills/agents do not have it** — those accept nothing but a real human answer, because they widen what may be indexed, destroy data irreversibly, or install files a future AI session will auto-load and follow, and `confirm` is an argument the agent supplies to itself. Those three are also marked as requiring user interaction, which Claude Code honors: run headless, it denies the call before it reaches griot, even with an allow rule for the tool. (Full policy table: [docs/mcp-capability-coverage.md § The management surface](docs/mcp-capability-coverage.md#the-management-surface).)
202
+
203
+ ### Claude Code / opencode skills and agent
204
+
205
+ ```bash
206
+ griot assist install # every project: detects Claude Code and/or opencode, installs into whichever is present
207
+ griot assist install --scope local # this project only, into ./.claude or ./.opencode
208
+ griot assist install --harness opencode # skip detection, target one harness explicitly
209
+ griot assist install --skills-only # copy the skills and the agent, and ask nothing
210
+ ```
211
+
212
+ After the files, the installer asks up to three things, in this order, each `[y/N]` with no as the default: registering the MCP server, letting the read-only tools run without a prompt, and (for every project only) the instructions block. The last two are offered only when the server is registered, since they are about its tools. It ends with a summary of what was done and what comes next. With no supported harness on the machine it installs nothing and exits with an error.
213
+
214
+ Copies a small bundle — five Skills (onboarding, indexing, day-to-day search/ask workflows, operations — running and recovering index runs from inside an agent session — and troubleshooting) and a setup Agent — written for whoever uses griot in **their own** project, not for contributing to griot itself. Claude Code gets `.claude/skills/`+`.claude/agents/`, opencode gets `.opencode/skills/`+`.opencode/agents/` (at `--scope global`: Claude Code's user directory, `~/.claude` or the one `CLAUDE_CONFIG_DIR` names, and `~/.config/opencode/`); Skills are one shared file per skill (both harnesses read the same `SKILL.md` layout), the setup Agent ships as two variants because the two harnesses use different frontmatter for a subagent definition. The same thing is also `griot_assist_install`, an MCP tool an already-connected agent can request on your behalf — it still needs a real human answer, for the same reason `repos_add`/`profiles_delete` do. Re-running it overwrites a file it installed before if griot's bundled version changed — including any edits you made to that file yourself; the command lists which files it overwrote.
215
+
216
+ At global scope, `griot assist install` also **offers** to add a short block to the harness's global instructions file (`~/.claude/CLAUDE.md` for Claude Code) that tells agents in every project when to use `griot_search`. It shows you the exact text and the file, and writes only if you type `y` at the prompt. With no interactive terminal (a script, a pipe) it writes nothing, and there is deliberately no flag that answers for you. That keeps the question from being skipped by accident or by an MCP tool. It is not a defence against a process that already has a shell on your machine: that process can edit the file directly, or drive a pseudo-terminal. `--no-instructions` skips the question. The block sits between `griot:begin` and `griot:end` markers, nothing outside them is touched, a symlinked file is written through, and deleting the block removes it. `griot_assist_install` (MCP) never touches this file.
217
+
218
+ Secrets are never an MCP operation. `griot_auth_guidance` tells an agent which providers are configured and which command you should run yourself; no tool takes or returns a key, masked or otherwise.
219
+
220
+ There is deliberately no `griot_ask` MCP tool: an agent calling MCP already has its own LLM — it needs retrieval, not a second synthesis layer.
221
+
222
+ ### Running multiple sessions
223
+
224
+ The vector store is embedded (no server), so only one process can hold a given collection open at a time. Subagents and workflow-spawned agents share their parent session's MCP connection and never collide with each other. A genuinely separate session (another window, another project) using the **same** embedding profile can collide, though, and so can a `griot index` run from a shell while a server is attached. By default (`GRIOT_MCP_CONCURRENCY_MODE=multi`) the server releases the collection once it has gone `GRIOT_MCP_IDLE_RELEASE_SECONDS` (default 30) without a tool call and retries with backoff when it reopens, so another session or a shell command gets in after that window. The cost is one reopen, roughly 90 ms on a 15,000-point collection, on the first call after an idle stretch. Set `GRIOT_MCP_CONCURRENCY_MODE=single` to hold the collection for the server's whole life instead: no reopen cost, but any other process on that profile gets a hard error until the session ends. To index from inside a session without waiting for the idle window, enable `griot_index_repo` (`GRIOT_MCP_ENABLE_INDEX=true`): it lets go of the server's handle before starting the run, once no other griot tool call is using the index (it waits a few seconds for one to finish, and otherwise asks to be called again). The `griot-operations` skill walks through this. Sessions on different embedding profiles never collide, since each profile is a separate collection.
225
+
226
+ ## Documentation
227
+
228
+ | | |
229
+ |---|---|
230
+ | [SECURITY.md](SECURITY.md) | What leaves your machine, what is protected on disk, and the MCP threat model |
231
+ | [ROADMAP.md](ROADMAP.md) | What is planned — and what was considered and rejected, with reasons |
232
+ | [docs/indexing-model.md](docs/indexing-model.md) | What a point is keyed by, what its payload carries, and why re-indexing is idempotent |
233
+ | [docs/mcp-capability-coverage.md](docs/mcp-capability-coverage.md) | Which MCP protocol capabilities griot uses, the CLI↔MCP parity table, and the confirmation policy |
234
+ | [docs/lessons-and-debts.md](docs/lessons-and-debts.md) | Decisions this project learned the hard way, and what it knowingly left undone |
235
+ | [CONTRIBUTING.md](CONTRIBUTING.md) | What the code expects from a change |
236
+ | [CHANGELOG.md](CHANGELOG.md) | Released changes |
237
+
238
+ ## Where things live
239
+
240
+ | Path | Contents |
241
+ |---|---|
242
+ | `~/.config/griot/` | `.env` (credentials, 0600), `repos.json`, `quality_golden_set.json` |
243
+ | `~/.local/share/griot/` | `qdrant_data/` (vectors + indexed content), `models/` (local embedding models), `logs/`, `.spend_state.json` |
244
+
245
+ Override with `GRIOT_CONFIG_DIR` / `GRIOT_DATA_DIR` (XDG variables are also honored). Everything griot writes is chmod 0600 (files) / 0700 (dirs).
246
+
247
+ ## Environment variables
248
+
249
+ `griot config list` shows every setting, the value in force and where it comes from (the environment, `<config>/.env`, or the default). `griot config set <name> <value>` checks a value and writes it to the file, `griot config unset <name>` goes back to the default, and `griot config get <name>` prints one value. A change that widens something is asked about at an interactive terminal, with no flag that answers: raising a spend ceiling, turning on indexing through MCP, adding a directory an agent may index, pointing a platform token at another host. A variable exported in the environment wins over the file, and a running MCP server keeps the values it started with: the `griot_config_list` tool answers for the server being asked, with the value each setting has there, where it came from, and whether the file has changed since. The embedding profile has its own command (`griot profiles use`), and credentials have `griot auth`.
250
+
251
+ The most used ones; `griot config list` shows them all.
252
+
253
+ | Variable | Purpose |
254
+ |---|---|
255
+ | `GRIOT_EMBED_PROFILE` | active embedding profile (default `jina-code`) |
256
+ | `GRIOT_CHAT_PROFILE` | active chat profile (default `gemini`) |
257
+ | `GRIOT_SPEND_CEILING_USD` | daily spend ceiling (default $3) |
258
+ | `GRIOT_SPEND_VELOCITY_CEILING_USD` | 5-minute window ceiling (default $1) |
259
+ | `GRIOT_LOG_QUESTIONS` | `false` omits question text from the query log |
260
+ | `GRIOT_PROJECT` | name recorded with each `griot ask`, `griot_search` and MCP tool call so `griot stats` can show usage by project (default: the folder `CLAUDE_PROJECT_DIR` names, else the folder `griot` runs in; set it in the `env` of that project's MCP server entry, not in `.env`) |
261
+ | `GRIOT_MCP_ENABLE_INDEX` | `true` enables the MCP indexing tool |
262
+ | `GRIOT_MCP_INDEX_ROOTS` | `:`-separated dir prefixes allowed for MCP indexing |
263
+ | `GRIOT_MCP_CONCURRENCY_MODE` | `multi` (default) or `single` — see "Running multiple sessions" above |
264
+ | `GRIOT_MCP_IDLE_RELEASE_SECONDS` | idle window before releasing the collection handle in `multi` mode (default 30) |
265
+ | `GRIOT_GITLAB_API_BASE` | self-hosted GitLab API base (default `https://gitlab.com/api/v4`) |
266
+ | `GRIOT_GITEA_HOSTS` | comma-separated Gitea/Forgejo hosts to recognize |
267
+
268
+ ## Quality tooling
269
+
270
+ ```bash
271
+ griot quality-check # self-check: sampled points must find themselves
272
+ griot golden-set suggest ~/code/my-app # derive curated test cases from that repository's git log (human-approved)
273
+ griot golden-set add "query" # curate a case from a real search
274
+ ```
275
+
276
+ `griot quality-check` scores retrieval against your curated golden set — useful before/after switching embedding profiles.
277
+
278
+ ### Credentials in indexed content
279
+
280
+ ```bash
281
+ griot audit # where the index holds credential-looking values (never the values)
282
+ ```
283
+
284
+ Text is scanned for credential-shaped values (private keys, a list of provider token formats, JWTs, passwords in URLs, random-looking values assigned to names like `API_KEY`) before it is embedded and stored, and they are replaced with a marker; the run tells you where. `griot audit` looks for the same shapes in what is already indexed. What this can and cannot find is in [SECURITY.md](SECURITY.md#credentials-in-what-is-indexed).
285
+
286
+ ## Development
287
+
288
+ ```bash
289
+ uv sync --locked --extra dev # the versions CI runs (or: pip install -e ".[dev]")
290
+ uv run pytest -q # no test ever calls a real API or needs credentials
291
+ ```
292
+
293
+ ## License
294
+
295
+ [Apache-2.0](LICENSE)