rag-your-code 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- rag_your_code-0.4.1/LICENSE +21 -0
- rag_your_code-0.4.1/PKG-INFO +237 -0
- rag_your_code-0.4.1/README.md +210 -0
- rag_your_code-0.4.1/pyproject.toml +53 -0
- rag_your_code-0.4.1/setup.cfg +4 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/PKG-INFO +237 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/SOURCES.txt +37 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/dependency_links.txt +1 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/entry_points.txt +2 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/requires.txt +6 -0
- rag_your_code-0.4.1/src/rag_your_code.egg-info/top_level.txt +1 -0
- rag_your_code-0.4.1/src/ragyourcode/__init__.py +6 -0
- rag_your_code-0.4.1/src/ragyourcode/agentic.py +55 -0
- rag_your_code-0.4.1/src/ragyourcode/annotate.py +35 -0
- rag_your_code-0.4.1/src/ragyourcode/cli.py +575 -0
- rag_your_code-0.4.1/src/ragyourcode/config.py +572 -0
- rag_your_code-0.4.1/src/ragyourcode/descriptions.py +248 -0
- rag_your_code-0.4.1/src/ragyourcode/embeddings.py +60 -0
- rag_your_code-0.4.1/src/ragyourcode/graph.py +198 -0
- rag_your_code-0.4.1/src/ragyourcode/indexer.py +411 -0
- rag_your_code-0.4.1/src/ragyourcode/models.py +86 -0
- rag_your_code-0.4.1/src/ragyourcode/parser.py +485 -0
- rag_your_code-0.4.1/src/ragyourcode/py.typed +0 -0
- rag_your_code-0.4.1/src/ragyourcode/search.py +131 -0
- rag_your_code-0.4.1/tests/test_agent_protocol.py +95 -0
- rag_your_code-0.4.1/tests/test_agentic.py +29 -0
- rag_your_code-0.4.1/tests/test_config.py +336 -0
- rag_your_code-0.4.1/tests/test_descriptions.py +342 -0
- rag_your_code-0.4.1/tests/test_e2e_cli.py +106 -0
- rag_your_code-0.4.1/tests/test_golden.py +31 -0
- rag_your_code-0.4.1/tests/test_graph_incremental.py +114 -0
- rag_your_code-0.4.1/tests/test_language_fixtures.py +110 -0
- rag_your_code-0.4.1/tests/test_large_repo.py +19 -0
- rag_your_code-0.4.1/tests/test_metadata.py +138 -0
- rag_your_code-0.4.1/tests/test_multilanguage.py +25 -0
- rag_your_code-0.4.1/tests/test_parser_edges.py +12 -0
- rag_your_code-0.4.1/tests/test_ragyourcode.py +109 -0
- rag_your_code-0.4.1/tests/test_resilience.py +116 -0
- rag_your_code-0.4.1/tests/test_retrieval_correctness.py +113 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 rag-your-code contributors
|
|
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.
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rag-your-code
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: A local, explainable RAG index for codebases and coding agents
|
|
5
|
+
Author: rag-your-code contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Keywords: rag,code-search,retrieval,indexing,graphrag,offline,explainable,agent
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
18
|
+
Classifier: Topic :: Text Processing :: Indexing
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7; extra == "dev"
|
|
25
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11" and extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# RAG Your Code
|
|
29
|
+
|
|
30
|
+
`rag-your-code` is the **R** in RAG: a local, explainable retrieval index over a
|
|
31
|
+
codebase. The generation half stays in your agent. It scans functions, methods
|
|
32
|
+
and classes across Python and fourteen other languages, assigns stable serial
|
|
33
|
+
numbers, and answers queries with a file, a line range, the terms that matched,
|
|
34
|
+
and the source itself.
|
|
35
|
+
|
|
36
|
+
No network calls and no runtime dependencies, by design rather than by
|
|
37
|
+
omission — it is meant to run over a private repository on a machine with the
|
|
38
|
+
network turned off, and to produce an index you can read.
|
|
39
|
+
|
|
40
|
+
## What the embedding does, and what it does not
|
|
41
|
+
|
|
42
|
+
This matters more than any feature list, so it is stated up front rather than
|
|
43
|
+
in a footnote.
|
|
44
|
+
|
|
45
|
+
The embedder is a **signed feature hash**: it hashes tokens into 384 buckets.
|
|
46
|
+
Cosine similarity over those vectors is therefore a normalised measure of
|
|
47
|
+
*token overlap*, and it carries no semantics whatever:
|
|
48
|
+
|
|
49
|
+
| pair | cosine |
|
|
50
|
+
|---|---|
|
|
51
|
+
| `retry failed card charge` vs itself | 1.0000 |
|
|
52
|
+
| `sum two numbers` vs `add a pair of integers` | **0.0000** |
|
|
53
|
+
| `计算两个数的和` vs `sum two numbers` | **0.0000** |
|
|
54
|
+
| `sum two numbers` vs `delete the user database table` | 0.0000 |
|
|
55
|
+
|
|
56
|
+
A trained embedding model scores row 2 around 0.8. Here a synonym pair and an
|
|
57
|
+
unrelated pair are indistinguishable, because zero shared tokens is zero either
|
|
58
|
+
way.
|
|
59
|
+
|
|
60
|
+
Retrieval works anyway, because **identifiers and docstrings are already
|
|
61
|
+
natural language**: `retry_charge` contains the words *retry* and *charge*. But
|
|
62
|
+
it reaches only concepts someone wrote down. Two mechanisms close the rest of
|
|
63
|
+
the gap, and neither of them is a model:
|
|
64
|
+
|
|
65
|
+
- **Your agent rewrites the query.** It has the conversation; turning "重试扣款"
|
|
66
|
+
into `retry charge payment gateway` costs it nothing.
|
|
67
|
+
- **Your agent writes the descriptions** (see below), which puts the missing
|
|
68
|
+
vocabulary into the index once instead of into every query.
|
|
69
|
+
|
|
70
|
+
## Quick start
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Not on PyPI. Take the wheel from the latest release, or install the source:
|
|
74
|
+
# https://github.com/skymanbp/rag-your-code/releases
|
|
75
|
+
pip install ./rag_your_code-0.4.0-py3-none-any.whl
|
|
76
|
+
# ... or, from a clone: python -m pip install -e .
|
|
77
|
+
|
|
78
|
+
rag-your-code index .
|
|
79
|
+
rag-your-code search "where are HTTP retries handled" --json
|
|
80
|
+
rag-your-code search "what calls the retry handler" --graph --hops 1 --json
|
|
81
|
+
rag-your-code annotate
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The index and annotations are written under `.rag-your-code/`; source files are
|
|
85
|
+
never modified. Use `--json` when feeding results to an agent.
|
|
86
|
+
|
|
87
|
+
For a large repository prefer `rag-your-code index . --compact`. Later
|
|
88
|
+
`index` runs and the agent's `refresh` reuse unchanged files and preserve
|
|
89
|
+
global serials; `--full` discards the cache.
|
|
90
|
+
|
|
91
|
+
## Agent-authored descriptions
|
|
92
|
+
|
|
93
|
+
Every unit carries a description, and that description is indexed. By default
|
|
94
|
+
it is generated without a model: the identifier humanised, the parameter and
|
|
95
|
+
callee names listed, the docstring appended. That introduces no vocabulary the
|
|
96
|
+
source did not already contain, which is exactly why retrieval cannot reach a
|
|
97
|
+
concept nobody wrote down.
|
|
98
|
+
|
|
99
|
+
The agent already reading this index can supply those words:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
rag-your-code describe status # coverage, and what is pending
|
|
103
|
+
rag-your-code describe export --limit 20 # a batch, with source and a brief
|
|
104
|
+
rag-your-code describe import written.json # store what the agent wrote
|
|
105
|
+
rag-your-code index . # apply it
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
or, in the JSON-lines protocol, `describe_pending` and `describe_put` — which
|
|
109
|
+
take effect in the same session, without a refresh.
|
|
110
|
+
|
|
111
|
+
Measured on the fixture repository, replacing one generated sentence with an
|
|
112
|
+
agent-written bilingual one:
|
|
113
|
+
|
|
114
|
+
| query | generated description | agent description |
|
|
115
|
+
|---|---|---|
|
|
116
|
+
| `exponential backoff` | no lexical evidence | **#1**, 1.0172 |
|
|
117
|
+
| `double billing safety` | no lexical evidence | **#1**, 0.3404 |
|
|
118
|
+
| `支付网关超时` | no lexical evidence | **#1**, 0.8632 |
|
|
119
|
+
|
|
120
|
+
**What this is:** it moves the semantic work from query time to index time.
|
|
121
|
+
Matching stays lexical — a description saying `retry` still cannot answer a
|
|
122
|
+
query saying `resend` unless the description also says so. It is LLM-authored
|
|
123
|
+
keyword expansion, and its reach is bounded by how many ways of saying the
|
|
124
|
+
thing the agent thought to write down.
|
|
125
|
+
|
|
126
|
+
Descriptions live in `rag-your-code.descriptions.json` at the repository root
|
|
127
|
+
and are meant to be committed, so one person's pass benefits everyone who
|
|
128
|
+
clones. Each is keyed by unit id **and a digest of the unit's source**: when
|
|
129
|
+
the code changes the description is not applied, the unit returns to the
|
|
130
|
+
pending queue, and retrieval falls back to the generated sentence. A
|
|
131
|
+
description that outlived its code would be a confident wrong answer, which is
|
|
132
|
+
the one thing this index is built not to give.
|
|
133
|
+
|
|
134
|
+
## Configuration
|
|
135
|
+
|
|
136
|
+
Twelve settings live in `rag-your-code.toml` at the repository root:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
rag-your-code config init # a commented file, all defaults
|
|
140
|
+
rag-your-code config list # effective values and their source
|
|
141
|
+
rag-your-code config set index.ignore '["vendor", "generated"]'
|
|
142
|
+
rag-your-code config set search.vector_weight 0.25
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Resolution is CLI flag > file > built-in default. There is no environment
|
|
146
|
+
layer: an index is an artifact of a repository, not of a shell.
|
|
147
|
+
|
|
148
|
+
| section | settings |
|
|
149
|
+
|---|---|
|
|
150
|
+
| `[index]` | `ignore`, `suffixes`, `max_file_bytes` |
|
|
151
|
+
| `[embedding]` | `dimensions` |
|
|
152
|
+
| `[search]` | `vector_weight`, `limit`, `max_chars` |
|
|
153
|
+
| `[agent]` | `max_open_bytes`, `max_open_chars` |
|
|
154
|
+
| `[describe]` | `languages`, `batch`, `max_chars` |
|
|
155
|
+
|
|
156
|
+
An unknown key or an out-of-range value is an error, not a shrug — a setting
|
|
157
|
+
that is silently dropped is indistinguishable from one that had no effect.
|
|
158
|
+
`index.suffixes` may only name suffixes the parser has rules for, because a
|
|
159
|
+
suffix it cannot read is walked, parsed to nothing, and reported as a clean
|
|
160
|
+
index of zero units.
|
|
161
|
+
|
|
162
|
+
The four settings under `[index]` and `[embedding]` determine what an index
|
|
163
|
+
*contains*, so a digest of them is recorded in the index and a change forces a
|
|
164
|
+
full rebuild. The rest take effect immediately and never invalidate anything.
|
|
165
|
+
|
|
166
|
+
## Agent protocol
|
|
167
|
+
|
|
168
|
+
`rag-your-code agent --root PATH` reads JSON lines from stdin and writes JSON
|
|
169
|
+
lines to stdout:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{"action":"search","query":"database transaction rollback","limit":5}
|
|
173
|
+
{"action":"research","query":"trace payment retry behavior","max_steps":2}
|
|
174
|
+
{"action":"neighbors","id":"payments.py:4:retry_charge","hops":1}
|
|
175
|
+
{"action":"open","path":"payments.py","start_line":1,"end_line":80}
|
|
176
|
+
{"action":"describe_pending","limit":20}
|
|
177
|
+
{"action":"describe_put","descriptions":[{"id":"payments.py:4:retry_charge","text":"..."}]}
|
|
178
|
+
{"action":"refresh"}
|
|
179
|
+
{"action":"stats"}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
No single request can end the session: numeric fields saturate at their bounds,
|
|
183
|
+
`open` is bounded in both lines and bytes, and anything unanticipated is
|
|
184
|
+
reported in-band with its exception type. Streams are pinned to UTF-8 rather
|
|
185
|
+
than following the OS codepage.
|
|
186
|
+
|
|
187
|
+
The bundled Claude plugin skill documents the recommended workflow: index at
|
|
188
|
+
session start, retrieve narrowly, inspect returned source, describe what is
|
|
189
|
+
pending, and re-index after substantial changes.
|
|
190
|
+
|
|
191
|
+
## Design notes
|
|
192
|
+
|
|
193
|
+
- Python uses the standard-library AST, so nested functions, methods, calls,
|
|
194
|
+
imports, signatures and source line ranges are precise.
|
|
195
|
+
- Other languages use a line-oriented declaration scanner: a per-language rule
|
|
196
|
+
table matched one line at a time, then a span closer (brace balance, Ruby's
|
|
197
|
+
`end`, or the next declaration). Because a pattern never sees a second line,
|
|
198
|
+
the reported line number is the scanner's own loop index and cannot drift,
|
|
199
|
+
and a declaration cannot swallow the ones after it. Fourteen languages are
|
|
200
|
+
covered and graded against source-controlled fixtures in
|
|
201
|
+
`tests/fixtures/languages/`; `SPEC.md` there states what counts as a unit.
|
|
202
|
+
- Retrieval combines lexical overlap and cosine similarity. Every result is
|
|
203
|
+
explainable: you can read why it matched.
|
|
204
|
+
- Schema 2 supports incremental per-file reuse, repository-global serials,
|
|
205
|
+
graph edges, and optional compact float32 vector storage (`index --compact`).
|
|
206
|
+
- GRAG expands bounded `calls`/`imports`/`contains` neighbours with edge-path
|
|
207
|
+
evidence, and omits an edge it cannot resolve rather than guessing one. ARAG
|
|
208
|
+
exposes bounded, observable `research`, `neighbors`, `open` and `refresh`.
|
|
209
|
+
- The generated `RAG[00001] ...` comments live in a sidecar Markdown file,
|
|
210
|
+
which avoids rewriting your code while preserving the numbered layer that
|
|
211
|
+
gets embedded.
|
|
212
|
+
|
|
213
|
+
## What lives where
|
|
214
|
+
|
|
215
|
+
| path | authored or generated | committed |
|
|
216
|
+
|---|---|---|
|
|
217
|
+
| `rag-your-code.toml` | authored | yes |
|
|
218
|
+
| `rag-your-code.descriptions.json` | authored by your agent | yes |
|
|
219
|
+
| `.rag-your-code/` (index, vectors, annotations) | generated | no |
|
|
220
|
+
|
|
221
|
+
Nothing authored lives under `.rag-your-code/`: that directory is what people
|
|
222
|
+
delete to clear the cache.
|
|
223
|
+
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
python -m pip install -e ".[dev]"
|
|
228
|
+
pytest -q
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
No runtime dependencies; `pytest` and, below Python 3.11, `tomli` come from the
|
|
232
|
+
`dev` extra. CI covers Python 3.10 through 3.13 on Linux and Windows and
|
|
233
|
+
installs the built wheel into a clean environment to check that the workflow
|
|
234
|
+
the bundled skill documents actually runs from a published artifact. See
|
|
235
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for what the golden set and the language
|
|
236
|
+
fixtures are protecting, and [docs/ROADMAP.md](docs/ROADMAP.md) for what is
|
|
237
|
+
deliberately not here yet.
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# RAG Your Code
|
|
2
|
+
|
|
3
|
+
`rag-your-code` is the **R** in RAG: a local, explainable retrieval index over a
|
|
4
|
+
codebase. The generation half stays in your agent. It scans functions, methods
|
|
5
|
+
and classes across Python and fourteen other languages, assigns stable serial
|
|
6
|
+
numbers, and answers queries with a file, a line range, the terms that matched,
|
|
7
|
+
and the source itself.
|
|
8
|
+
|
|
9
|
+
No network calls and no runtime dependencies, by design rather than by
|
|
10
|
+
omission — it is meant to run over a private repository on a machine with the
|
|
11
|
+
network turned off, and to produce an index you can read.
|
|
12
|
+
|
|
13
|
+
## What the embedding does, and what it does not
|
|
14
|
+
|
|
15
|
+
This matters more than any feature list, so it is stated up front rather than
|
|
16
|
+
in a footnote.
|
|
17
|
+
|
|
18
|
+
The embedder is a **signed feature hash**: it hashes tokens into 384 buckets.
|
|
19
|
+
Cosine similarity over those vectors is therefore a normalised measure of
|
|
20
|
+
*token overlap*, and it carries no semantics whatever:
|
|
21
|
+
|
|
22
|
+
| pair | cosine |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `retry failed card charge` vs itself | 1.0000 |
|
|
25
|
+
| `sum two numbers` vs `add a pair of integers` | **0.0000** |
|
|
26
|
+
| `计算两个数的和` vs `sum two numbers` | **0.0000** |
|
|
27
|
+
| `sum two numbers` vs `delete the user database table` | 0.0000 |
|
|
28
|
+
|
|
29
|
+
A trained embedding model scores row 2 around 0.8. Here a synonym pair and an
|
|
30
|
+
unrelated pair are indistinguishable, because zero shared tokens is zero either
|
|
31
|
+
way.
|
|
32
|
+
|
|
33
|
+
Retrieval works anyway, because **identifiers and docstrings are already
|
|
34
|
+
natural language**: `retry_charge` contains the words *retry* and *charge*. But
|
|
35
|
+
it reaches only concepts someone wrote down. Two mechanisms close the rest of
|
|
36
|
+
the gap, and neither of them is a model:
|
|
37
|
+
|
|
38
|
+
- **Your agent rewrites the query.** It has the conversation; turning "重试扣款"
|
|
39
|
+
into `retry charge payment gateway` costs it nothing.
|
|
40
|
+
- **Your agent writes the descriptions** (see below), which puts the missing
|
|
41
|
+
vocabulary into the index once instead of into every query.
|
|
42
|
+
|
|
43
|
+
## Quick start
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Not on PyPI. Take the wheel from the latest release, or install the source:
|
|
47
|
+
# https://github.com/skymanbp/rag-your-code/releases
|
|
48
|
+
pip install ./rag_your_code-0.4.0-py3-none-any.whl
|
|
49
|
+
# ... or, from a clone: python -m pip install -e .
|
|
50
|
+
|
|
51
|
+
rag-your-code index .
|
|
52
|
+
rag-your-code search "where are HTTP retries handled" --json
|
|
53
|
+
rag-your-code search "what calls the retry handler" --graph --hops 1 --json
|
|
54
|
+
rag-your-code annotate
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The index and annotations are written under `.rag-your-code/`; source files are
|
|
58
|
+
never modified. Use `--json` when feeding results to an agent.
|
|
59
|
+
|
|
60
|
+
For a large repository prefer `rag-your-code index . --compact`. Later
|
|
61
|
+
`index` runs and the agent's `refresh` reuse unchanged files and preserve
|
|
62
|
+
global serials; `--full` discards the cache.
|
|
63
|
+
|
|
64
|
+
## Agent-authored descriptions
|
|
65
|
+
|
|
66
|
+
Every unit carries a description, and that description is indexed. By default
|
|
67
|
+
it is generated without a model: the identifier humanised, the parameter and
|
|
68
|
+
callee names listed, the docstring appended. That introduces no vocabulary the
|
|
69
|
+
source did not already contain, which is exactly why retrieval cannot reach a
|
|
70
|
+
concept nobody wrote down.
|
|
71
|
+
|
|
72
|
+
The agent already reading this index can supply those words:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
rag-your-code describe status # coverage, and what is pending
|
|
76
|
+
rag-your-code describe export --limit 20 # a batch, with source and a brief
|
|
77
|
+
rag-your-code describe import written.json # store what the agent wrote
|
|
78
|
+
rag-your-code index . # apply it
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
or, in the JSON-lines protocol, `describe_pending` and `describe_put` — which
|
|
82
|
+
take effect in the same session, without a refresh.
|
|
83
|
+
|
|
84
|
+
Measured on the fixture repository, replacing one generated sentence with an
|
|
85
|
+
agent-written bilingual one:
|
|
86
|
+
|
|
87
|
+
| query | generated description | agent description |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `exponential backoff` | no lexical evidence | **#1**, 1.0172 |
|
|
90
|
+
| `double billing safety` | no lexical evidence | **#1**, 0.3404 |
|
|
91
|
+
| `支付网关超时` | no lexical evidence | **#1**, 0.8632 |
|
|
92
|
+
|
|
93
|
+
**What this is:** it moves the semantic work from query time to index time.
|
|
94
|
+
Matching stays lexical — a description saying `retry` still cannot answer a
|
|
95
|
+
query saying `resend` unless the description also says so. It is LLM-authored
|
|
96
|
+
keyword expansion, and its reach is bounded by how many ways of saying the
|
|
97
|
+
thing the agent thought to write down.
|
|
98
|
+
|
|
99
|
+
Descriptions live in `rag-your-code.descriptions.json` at the repository root
|
|
100
|
+
and are meant to be committed, so one person's pass benefits everyone who
|
|
101
|
+
clones. Each is keyed by unit id **and a digest of the unit's source**: when
|
|
102
|
+
the code changes the description is not applied, the unit returns to the
|
|
103
|
+
pending queue, and retrieval falls back to the generated sentence. A
|
|
104
|
+
description that outlived its code would be a confident wrong answer, which is
|
|
105
|
+
the one thing this index is built not to give.
|
|
106
|
+
|
|
107
|
+
## Configuration
|
|
108
|
+
|
|
109
|
+
Twelve settings live in `rag-your-code.toml` at the repository root:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
rag-your-code config init # a commented file, all defaults
|
|
113
|
+
rag-your-code config list # effective values and their source
|
|
114
|
+
rag-your-code config set index.ignore '["vendor", "generated"]'
|
|
115
|
+
rag-your-code config set search.vector_weight 0.25
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Resolution is CLI flag > file > built-in default. There is no environment
|
|
119
|
+
layer: an index is an artifact of a repository, not of a shell.
|
|
120
|
+
|
|
121
|
+
| section | settings |
|
|
122
|
+
|---|---|
|
|
123
|
+
| `[index]` | `ignore`, `suffixes`, `max_file_bytes` |
|
|
124
|
+
| `[embedding]` | `dimensions` |
|
|
125
|
+
| `[search]` | `vector_weight`, `limit`, `max_chars` |
|
|
126
|
+
| `[agent]` | `max_open_bytes`, `max_open_chars` |
|
|
127
|
+
| `[describe]` | `languages`, `batch`, `max_chars` |
|
|
128
|
+
|
|
129
|
+
An unknown key or an out-of-range value is an error, not a shrug — a setting
|
|
130
|
+
that is silently dropped is indistinguishable from one that had no effect.
|
|
131
|
+
`index.suffixes` may only name suffixes the parser has rules for, because a
|
|
132
|
+
suffix it cannot read is walked, parsed to nothing, and reported as a clean
|
|
133
|
+
index of zero units.
|
|
134
|
+
|
|
135
|
+
The four settings under `[index]` and `[embedding]` determine what an index
|
|
136
|
+
*contains*, so a digest of them is recorded in the index and a change forces a
|
|
137
|
+
full rebuild. The rest take effect immediately and never invalidate anything.
|
|
138
|
+
|
|
139
|
+
## Agent protocol
|
|
140
|
+
|
|
141
|
+
`rag-your-code agent --root PATH` reads JSON lines from stdin and writes JSON
|
|
142
|
+
lines to stdout:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{"action":"search","query":"database transaction rollback","limit":5}
|
|
146
|
+
{"action":"research","query":"trace payment retry behavior","max_steps":2}
|
|
147
|
+
{"action":"neighbors","id":"payments.py:4:retry_charge","hops":1}
|
|
148
|
+
{"action":"open","path":"payments.py","start_line":1,"end_line":80}
|
|
149
|
+
{"action":"describe_pending","limit":20}
|
|
150
|
+
{"action":"describe_put","descriptions":[{"id":"payments.py:4:retry_charge","text":"..."}]}
|
|
151
|
+
{"action":"refresh"}
|
|
152
|
+
{"action":"stats"}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
No single request can end the session: numeric fields saturate at their bounds,
|
|
156
|
+
`open` is bounded in both lines and bytes, and anything unanticipated is
|
|
157
|
+
reported in-band with its exception type. Streams are pinned to UTF-8 rather
|
|
158
|
+
than following the OS codepage.
|
|
159
|
+
|
|
160
|
+
The bundled Claude plugin skill documents the recommended workflow: index at
|
|
161
|
+
session start, retrieve narrowly, inspect returned source, describe what is
|
|
162
|
+
pending, and re-index after substantial changes.
|
|
163
|
+
|
|
164
|
+
## Design notes
|
|
165
|
+
|
|
166
|
+
- Python uses the standard-library AST, so nested functions, methods, calls,
|
|
167
|
+
imports, signatures and source line ranges are precise.
|
|
168
|
+
- Other languages use a line-oriented declaration scanner: a per-language rule
|
|
169
|
+
table matched one line at a time, then a span closer (brace balance, Ruby's
|
|
170
|
+
`end`, or the next declaration). Because a pattern never sees a second line,
|
|
171
|
+
the reported line number is the scanner's own loop index and cannot drift,
|
|
172
|
+
and a declaration cannot swallow the ones after it. Fourteen languages are
|
|
173
|
+
covered and graded against source-controlled fixtures in
|
|
174
|
+
`tests/fixtures/languages/`; `SPEC.md` there states what counts as a unit.
|
|
175
|
+
- Retrieval combines lexical overlap and cosine similarity. Every result is
|
|
176
|
+
explainable: you can read why it matched.
|
|
177
|
+
- Schema 2 supports incremental per-file reuse, repository-global serials,
|
|
178
|
+
graph edges, and optional compact float32 vector storage (`index --compact`).
|
|
179
|
+
- GRAG expands bounded `calls`/`imports`/`contains` neighbours with edge-path
|
|
180
|
+
evidence, and omits an edge it cannot resolve rather than guessing one. ARAG
|
|
181
|
+
exposes bounded, observable `research`, `neighbors`, `open` and `refresh`.
|
|
182
|
+
- The generated `RAG[00001] ...` comments live in a sidecar Markdown file,
|
|
183
|
+
which avoids rewriting your code while preserving the numbered layer that
|
|
184
|
+
gets embedded.
|
|
185
|
+
|
|
186
|
+
## What lives where
|
|
187
|
+
|
|
188
|
+
| path | authored or generated | committed |
|
|
189
|
+
|---|---|---|
|
|
190
|
+
| `rag-your-code.toml` | authored | yes |
|
|
191
|
+
| `rag-your-code.descriptions.json` | authored by your agent | yes |
|
|
192
|
+
| `.rag-your-code/` (index, vectors, annotations) | generated | no |
|
|
193
|
+
|
|
194
|
+
Nothing authored lives under `.rag-your-code/`: that directory is what people
|
|
195
|
+
delete to clear the cache.
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
python -m pip install -e ".[dev]"
|
|
201
|
+
pytest -q
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
No runtime dependencies; `pytest` and, below Python 3.11, `tomli` come from the
|
|
205
|
+
`dev` extra. CI covers Python 3.10 through 3.13 on Linux and Windows and
|
|
206
|
+
installs the built wheel into a clean environment to check that the workflow
|
|
207
|
+
the bundled skill documents actually runs from a published artifact. See
|
|
208
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) for what the golden set and the language
|
|
209
|
+
fixtures are protecting, and [docs/ROADMAP.md](docs/ROADMAP.md) for what is
|
|
210
|
+
deliberately not here yet.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# 77 is the floor for PEP 639 `license` / `license-files`, which is what puts
|
|
3
|
+
# the MIT text into the built wheel rather than only naming it in metadata.
|
|
4
|
+
requires = ["setuptools>=77"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "rag-your-code"
|
|
9
|
+
version = "0.4.1"
|
|
10
|
+
description = "A local, explainable RAG index for codebases and coding agents"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.10"
|
|
13
|
+
license = "MIT"
|
|
14
|
+
license-files = ["LICENSE"]
|
|
15
|
+
authors = [{name = "rag-your-code contributors"}]
|
|
16
|
+
keywords = ["rag", "code-search", "retrieval", "indexing", "graphrag", "offline", "explainable", "agent"]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Environment :: Console",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.10",
|
|
24
|
+
"Programming Language :: Python :: 3.11",
|
|
25
|
+
"Programming Language :: Python :: 3.12",
|
|
26
|
+
"Programming Language :: Python :: 3.13",
|
|
27
|
+
"Topic :: Software Development :: Libraries",
|
|
28
|
+
"Topic :: Text Processing :: Indexing",
|
|
29
|
+
"Typing :: Typed",
|
|
30
|
+
]
|
|
31
|
+
dependencies = []
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
# `pytest` is what README and docs/TESTING.md tell a contributor to run, so it
|
|
35
|
+
# has to be declared somewhere installable. `tomli` covers the one test that
|
|
36
|
+
# reads pyproject.toml on 3.10, where `tomllib` does not exist yet.
|
|
37
|
+
dev = [
|
|
38
|
+
"pytest>=7",
|
|
39
|
+
"tomli>=2.0; python_version < '3.11'",
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.scripts]
|
|
43
|
+
rag-your-code = "ragyourcode.cli:main"
|
|
44
|
+
|
|
45
|
+
[tool.setuptools.packages.find]
|
|
46
|
+
where = ["src"]
|
|
47
|
+
|
|
48
|
+
[tool.setuptools.package-data]
|
|
49
|
+
ragyourcode = ["py.typed"]
|
|
50
|
+
|
|
51
|
+
[tool.pytest.ini_options]
|
|
52
|
+
testpaths = ["tests"]
|
|
53
|
+
pythonpath = ["src", "."]
|