agent-booster 0.1.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.
- agent_booster-0.1.0/LICENSE +21 -0
- agent_booster-0.1.0/PKG-INFO +269 -0
- agent_booster-0.1.0/README.md +239 -0
- agent_booster-0.1.0/agent_booster.egg-info/PKG-INFO +269 -0
- agent_booster-0.1.0/agent_booster.egg-info/SOURCES.txt +14 -0
- agent_booster-0.1.0/agent_booster.egg-info/dependency_links.txt +1 -0
- agent_booster-0.1.0/agent_booster.egg-info/entry_points.txt +2 -0
- agent_booster-0.1.0/agent_booster.egg-info/requires.txt +7 -0
- agent_booster-0.1.0/agent_booster.egg-info/top_level.txt +1 -0
- agent_booster-0.1.0/booster/__init__.py +0 -0
- agent_booster-0.1.0/booster/cli.py +91 -0
- agent_booster-0.1.0/booster/indexer.py +115 -0
- agent_booster-0.1.0/booster/mcp_server.py +95 -0
- agent_booster-0.1.0/booster/retriever.py +31 -0
- agent_booster-0.1.0/pyproject.toml +44 -0
- agent_booster-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Sudhi Seshachala
|
|
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,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-booster
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AST+vector context router for AI coding agents — cut token costs 5-15x
|
|
5
|
+
Author-email: Sudhi Seshachala <Sudhi@b2bsphere.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sseshachala/conductai
|
|
8
|
+
Project-URL: Repository, https://github.com/sseshachala/conductai
|
|
9
|
+
Project-URL: Issues, https://github.com/sseshachala/conductai/issues
|
|
10
|
+
Keywords: ai,llm,claude,cursor,codex,mcp,tokens,ast
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: tree-sitter>=0.23
|
|
23
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
24
|
+
Requires-Dist: tree-sitter-typescript>=0.23
|
|
25
|
+
Requires-Dist: click>=8.1
|
|
26
|
+
Requires-Dist: mcp>=1.0
|
|
27
|
+
Requires-Dist: numpy>=1.26
|
|
28
|
+
Requires-Dist: anthropic>=0.40
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Agent Booster
|
|
32
|
+
|
|
33
|
+
Cut AI coding agent token costs 5–15x by routing only the code that matters.
|
|
34
|
+
|
|
35
|
+
Instead of sending full source files to the model on every read, Agent Booster builds a symbol index of your codebase and returns only the functions and classes relevant to the current task.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Without Booster With Booster
|
|
43
|
+
───────────────── ────────────────────────────
|
|
44
|
+
Read executor.py Read executor.py + task hint
|
|
45
|
+
→ 1,881 lines (~6k tokens) → 3 matching functions (~200 tokens)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Five layers work together:
|
|
49
|
+
|
|
50
|
+
| Layer | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| **Symbol index** | tree-sitter parses every `.py` file, extracts functions/classes into SQLite |
|
|
53
|
+
| **Semantic diff** | only re-indexes files that changed since last run |
|
|
54
|
+
| **Smart read** | given a file + task description, returns only matching symbol line ranges |
|
|
55
|
+
| **MCP server** | exposes tools over stdio so any MCP-compatible agent can call them |
|
|
56
|
+
| **Platform init** | one command writes the right config for Claude Code, Cursor, or Codex |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Requires Python 3.10+.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e tools/booster
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Verify:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
booster --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quickstart
|
|
77
|
+
|
|
78
|
+
**Step 1 — Index your codebase**
|
|
79
|
+
|
|
80
|
+
Run once from your project root. Re-run after large refactors.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
booster index
|
|
84
|
+
# Indexed 166 files, 1107 symbols.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The index is stored at `.booster/symbols.db` (SQLite, gitignored).
|
|
88
|
+
|
|
89
|
+
**Step 2 — Wire up your AI tool**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
booster init claude # Claude Code
|
|
93
|
+
booster init cursor # Cursor
|
|
94
|
+
booster init codex # OpenAI Codex CLI
|
|
95
|
+
booster init all # print all three
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Each command prints the JSON config snippet to paste into the right file. For Claude Code, copy the output into `.mcp.json` at your project root (or use the pre-wired `.mcp.json` already in this repo).
|
|
99
|
+
|
|
100
|
+
**Step 3 — Restart your AI tool**
|
|
101
|
+
|
|
102
|
+
The `agent-booster` MCP server will be available in every session. No further setup needed.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## CLI reference
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
booster index
|
|
110
|
+
```
|
|
111
|
+
Scans all `.py` files from the current directory, extracts functions and classes, stores in `.booster/symbols.db`. Skips `node_modules`, `.venv`, `__pycache__`, `.git`, `.booster`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
booster search "<query>"
|
|
117
|
+
```
|
|
118
|
+
Keyword search across all indexed symbols. Returns file path, line number, kind, name, and signature.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
booster search "workflow execute"
|
|
122
|
+
# apps/api/app/runtime/executor.py:1165 function _execute_output def _execute_output(...)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
booster serve
|
|
129
|
+
```
|
|
130
|
+
Starts the MCP server over stdio. Claude Code, Cursor, and Codex connect to this automatically when configured via `booster init`.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
booster init <platform>
|
|
136
|
+
```
|
|
137
|
+
Prints the MCP config snippet for the target platform. `platform` is one of: `claude`, `cursor`, `codex`, `all`.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
booster gain
|
|
143
|
+
```
|
|
144
|
+
Shows token savings statistics from past sessions. (Full analytics in a future release — currently a stub.)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## MCP tools
|
|
149
|
+
|
|
150
|
+
Once `booster serve` is running, these tools are available to the agent:
|
|
151
|
+
|
|
152
|
+
### `get_symbols(file)`
|
|
153
|
+
Returns all indexed symbols for a file — name, kind, line range, and signature.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Input: { "file": "apps/api/app/runtime/executor.py" }
|
|
157
|
+
Output: function run_workflow (lines 42-89): def run_workflow(...)
|
|
158
|
+
class WorkflowState (lines 91-140): class WorkflowState:
|
|
159
|
+
...
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `search_context(task)`
|
|
163
|
+
Keyword search across all symbols in the index. Returns top 10 matches with file locations.
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Input: { "task": "authenticate user token" }
|
|
167
|
+
Output: apps/api/app/auth/middleware.py:34 function verify_token — def verify_token(...)
|
|
168
|
+
...
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `smart_read(file, task)`
|
|
172
|
+
Returns only the lines of a file that are relevant to the task. Falls back to full file content if no symbols match.
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Input: { "file": "apps/api/app/runtime/executor.py", "task": "execute output block" }
|
|
176
|
+
Output: # function _execute_output (lines 1165-1210)
|
|
177
|
+
def _execute_output(block, state, credentials, ...):
|
|
178
|
+
...
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Platform config details
|
|
184
|
+
|
|
185
|
+
### Claude Code
|
|
186
|
+
|
|
187
|
+
Add to `.mcp.json` in your project root:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcpServers": {
|
|
192
|
+
"agent-booster": {
|
|
193
|
+
"command": "booster",
|
|
194
|
+
"args": ["serve"]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Cursor
|
|
201
|
+
|
|
202
|
+
Add to `.cursor/mcp.json`:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"mcpServers": {
|
|
207
|
+
"agent-booster": {
|
|
208
|
+
"command": "booster",
|
|
209
|
+
"args": ["serve"]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### OpenAI Codex CLI
|
|
216
|
+
|
|
217
|
+
Add to `~/.codex/config.json`:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"mcp": {
|
|
222
|
+
"servers": {
|
|
223
|
+
"agent-booster": {
|
|
224
|
+
"command": "booster",
|
|
225
|
+
"args": ["serve"]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Where it fits
|
|
235
|
+
|
|
236
|
+
Agent Booster is the third layer in a three-layer token reduction stack — each layer is independent and addable separately:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Layer 3 — Agent Booster AST+semantic routing, smart file reads
|
|
240
|
+
Layer 2 — RTK Token compression on tool output
|
|
241
|
+
Layer 1 — Prompt caching Stable context reuse (native to Claude Code + API)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Project layout
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
tools/booster/
|
|
250
|
+
├── README.md
|
|
251
|
+
├── pyproject.toml
|
|
252
|
+
└── booster/
|
|
253
|
+
├── __init__.py
|
|
254
|
+
├── cli.py # click commands: index, search, serve, init, gain
|
|
255
|
+
├── indexer.py # tree-sitter parser + SQLite symbol store
|
|
256
|
+
├── retriever.py # smart_read: task description → relevant line slice
|
|
257
|
+
└── mcp_server.py # MCP server exposing get_symbols, search_context, smart_read
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Roadmap
|
|
263
|
+
|
|
264
|
+
- [ ] TypeScript/TSX support (tree-sitter-typescript)
|
|
265
|
+
- [ ] Vector embeddings for semantic (not just keyword) search
|
|
266
|
+
- [ ] Smart model routing (`route_model` tool: Haiku / Sonnet / Opus)
|
|
267
|
+
- [ ] `booster gain` — real token savings analytics
|
|
268
|
+
- [ ] Watch mode: auto re-index on file save
|
|
269
|
+
- [ ] Publish to PyPI as `agent-booster`
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Agent Booster
|
|
2
|
+
|
|
3
|
+
Cut AI coding agent token costs 5–15x by routing only the code that matters.
|
|
4
|
+
|
|
5
|
+
Instead of sending full source files to the model on every read, Agent Booster builds a symbol index of your codebase and returns only the functions and classes relevant to the current task.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
Without Booster With Booster
|
|
13
|
+
───────────────── ────────────────────────────
|
|
14
|
+
Read executor.py Read executor.py + task hint
|
|
15
|
+
→ 1,881 lines (~6k tokens) → 3 matching functions (~200 tokens)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Five layers work together:
|
|
19
|
+
|
|
20
|
+
| Layer | What it does |
|
|
21
|
+
|---|---|
|
|
22
|
+
| **Symbol index** | tree-sitter parses every `.py` file, extracts functions/classes into SQLite |
|
|
23
|
+
| **Semantic diff** | only re-indexes files that changed since last run |
|
|
24
|
+
| **Smart read** | given a file + task description, returns only matching symbol line ranges |
|
|
25
|
+
| **MCP server** | exposes tools over stdio so any MCP-compatible agent can call them |
|
|
26
|
+
| **Platform init** | one command writes the right config for Claude Code, Cursor, or Codex |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
Requires Python 3.10+.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
pip install -e tools/booster
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Verify:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
booster --help
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Quickstart
|
|
47
|
+
|
|
48
|
+
**Step 1 — Index your codebase**
|
|
49
|
+
|
|
50
|
+
Run once from your project root. Re-run after large refactors.
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
booster index
|
|
54
|
+
# Indexed 166 files, 1107 symbols.
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
The index is stored at `.booster/symbols.db` (SQLite, gitignored).
|
|
58
|
+
|
|
59
|
+
**Step 2 — Wire up your AI tool**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
booster init claude # Claude Code
|
|
63
|
+
booster init cursor # Cursor
|
|
64
|
+
booster init codex # OpenAI Codex CLI
|
|
65
|
+
booster init all # print all three
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Each command prints the JSON config snippet to paste into the right file. For Claude Code, copy the output into `.mcp.json` at your project root (or use the pre-wired `.mcp.json` already in this repo).
|
|
69
|
+
|
|
70
|
+
**Step 3 — Restart your AI tool**
|
|
71
|
+
|
|
72
|
+
The `agent-booster` MCP server will be available in every session. No further setup needed.
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## CLI reference
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
booster index
|
|
80
|
+
```
|
|
81
|
+
Scans all `.py` files from the current directory, extracts functions and classes, stores in `.booster/symbols.db`. Skips `node_modules`, `.venv`, `__pycache__`, `.git`, `.booster`.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
booster search "<query>"
|
|
87
|
+
```
|
|
88
|
+
Keyword search across all indexed symbols. Returns file path, line number, kind, name, and signature.
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
booster search "workflow execute"
|
|
92
|
+
# apps/api/app/runtime/executor.py:1165 function _execute_output def _execute_output(...)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
booster serve
|
|
99
|
+
```
|
|
100
|
+
Starts the MCP server over stdio. Claude Code, Cursor, and Codex connect to this automatically when configured via `booster init`.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
booster init <platform>
|
|
106
|
+
```
|
|
107
|
+
Prints the MCP config snippet for the target platform. `platform` is one of: `claude`, `cursor`, `codex`, `all`.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
booster gain
|
|
113
|
+
```
|
|
114
|
+
Shows token savings statistics from past sessions. (Full analytics in a future release — currently a stub.)
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## MCP tools
|
|
119
|
+
|
|
120
|
+
Once `booster serve` is running, these tools are available to the agent:
|
|
121
|
+
|
|
122
|
+
### `get_symbols(file)`
|
|
123
|
+
Returns all indexed symbols for a file — name, kind, line range, and signature.
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
Input: { "file": "apps/api/app/runtime/executor.py" }
|
|
127
|
+
Output: function run_workflow (lines 42-89): def run_workflow(...)
|
|
128
|
+
class WorkflowState (lines 91-140): class WorkflowState:
|
|
129
|
+
...
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `search_context(task)`
|
|
133
|
+
Keyword search across all symbols in the index. Returns top 10 matches with file locations.
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Input: { "task": "authenticate user token" }
|
|
137
|
+
Output: apps/api/app/auth/middleware.py:34 function verify_token — def verify_token(...)
|
|
138
|
+
...
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### `smart_read(file, task)`
|
|
142
|
+
Returns only the lines of a file that are relevant to the task. Falls back to full file content if no symbols match.
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
Input: { "file": "apps/api/app/runtime/executor.py", "task": "execute output block" }
|
|
146
|
+
Output: # function _execute_output (lines 1165-1210)
|
|
147
|
+
def _execute_output(block, state, credentials, ...):
|
|
148
|
+
...
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Platform config details
|
|
154
|
+
|
|
155
|
+
### Claude Code
|
|
156
|
+
|
|
157
|
+
Add to `.mcp.json` in your project root:
|
|
158
|
+
|
|
159
|
+
```json
|
|
160
|
+
{
|
|
161
|
+
"mcpServers": {
|
|
162
|
+
"agent-booster": {
|
|
163
|
+
"command": "booster",
|
|
164
|
+
"args": ["serve"]
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Cursor
|
|
171
|
+
|
|
172
|
+
Add to `.cursor/mcp.json`:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{
|
|
176
|
+
"mcpServers": {
|
|
177
|
+
"agent-booster": {
|
|
178
|
+
"command": "booster",
|
|
179
|
+
"args": ["serve"]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### OpenAI Codex CLI
|
|
186
|
+
|
|
187
|
+
Add to `~/.codex/config.json`:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcp": {
|
|
192
|
+
"servers": {
|
|
193
|
+
"agent-booster": {
|
|
194
|
+
"command": "booster",
|
|
195
|
+
"args": ["serve"]
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Where it fits
|
|
205
|
+
|
|
206
|
+
Agent Booster is the third layer in a three-layer token reduction stack — each layer is independent and addable separately:
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
Layer 3 — Agent Booster AST+semantic routing, smart file reads
|
|
210
|
+
Layer 2 — RTK Token compression on tool output
|
|
211
|
+
Layer 1 — Prompt caching Stable context reuse (native to Claude Code + API)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## Project layout
|
|
217
|
+
|
|
218
|
+
```
|
|
219
|
+
tools/booster/
|
|
220
|
+
├── README.md
|
|
221
|
+
├── pyproject.toml
|
|
222
|
+
└── booster/
|
|
223
|
+
├── __init__.py
|
|
224
|
+
├── cli.py # click commands: index, search, serve, init, gain
|
|
225
|
+
├── indexer.py # tree-sitter parser + SQLite symbol store
|
|
226
|
+
├── retriever.py # smart_read: task description → relevant line slice
|
|
227
|
+
└── mcp_server.py # MCP server exposing get_symbols, search_context, smart_read
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## Roadmap
|
|
233
|
+
|
|
234
|
+
- [ ] TypeScript/TSX support (tree-sitter-typescript)
|
|
235
|
+
- [ ] Vector embeddings for semantic (not just keyword) search
|
|
236
|
+
- [ ] Smart model routing (`route_model` tool: Haiku / Sonnet / Opus)
|
|
237
|
+
- [ ] `booster gain` — real token savings analytics
|
|
238
|
+
- [ ] Watch mode: auto re-index on file save
|
|
239
|
+
- [ ] Publish to PyPI as `agent-booster`
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agent-booster
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: AST+vector context router for AI coding agents — cut token costs 5-15x
|
|
5
|
+
Author-email: Sudhi Seshachala <Sudhi@b2bsphere.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/sseshachala/conductai
|
|
8
|
+
Project-URL: Repository, https://github.com/sseshachala/conductai
|
|
9
|
+
Project-URL: Issues, https://github.com/sseshachala/conductai/issues
|
|
10
|
+
Keywords: ai,llm,claude,cursor,codex,mcp,tokens,ast
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Description-Content-Type: text/markdown
|
|
21
|
+
License-File: LICENSE
|
|
22
|
+
Requires-Dist: tree-sitter>=0.23
|
|
23
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
24
|
+
Requires-Dist: tree-sitter-typescript>=0.23
|
|
25
|
+
Requires-Dist: click>=8.1
|
|
26
|
+
Requires-Dist: mcp>=1.0
|
|
27
|
+
Requires-Dist: numpy>=1.26
|
|
28
|
+
Requires-Dist: anthropic>=0.40
|
|
29
|
+
Dynamic: license-file
|
|
30
|
+
|
|
31
|
+
# Agent Booster
|
|
32
|
+
|
|
33
|
+
Cut AI coding agent token costs 5–15x by routing only the code that matters.
|
|
34
|
+
|
|
35
|
+
Instead of sending full source files to the model on every read, Agent Booster builds a symbol index of your codebase and returns only the functions and classes relevant to the current task.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## How it works
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
Without Booster With Booster
|
|
43
|
+
───────────────── ────────────────────────────
|
|
44
|
+
Read executor.py Read executor.py + task hint
|
|
45
|
+
→ 1,881 lines (~6k tokens) → 3 matching functions (~200 tokens)
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Five layers work together:
|
|
49
|
+
|
|
50
|
+
| Layer | What it does |
|
|
51
|
+
|---|---|
|
|
52
|
+
| **Symbol index** | tree-sitter parses every `.py` file, extracts functions/classes into SQLite |
|
|
53
|
+
| **Semantic diff** | only re-indexes files that changed since last run |
|
|
54
|
+
| **Smart read** | given a file + task description, returns only matching symbol line ranges |
|
|
55
|
+
| **MCP server** | exposes tools over stdio so any MCP-compatible agent can call them |
|
|
56
|
+
| **Platform init** | one command writes the right config for Claude Code, Cursor, or Codex |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Requires Python 3.10+.
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install -e tools/booster
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Verify:
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
booster --help
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## Quickstart
|
|
77
|
+
|
|
78
|
+
**Step 1 — Index your codebase**
|
|
79
|
+
|
|
80
|
+
Run once from your project root. Re-run after large refactors.
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
booster index
|
|
84
|
+
# Indexed 166 files, 1107 symbols.
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The index is stored at `.booster/symbols.db` (SQLite, gitignored).
|
|
88
|
+
|
|
89
|
+
**Step 2 — Wire up your AI tool**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
booster init claude # Claude Code
|
|
93
|
+
booster init cursor # Cursor
|
|
94
|
+
booster init codex # OpenAI Codex CLI
|
|
95
|
+
booster init all # print all three
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Each command prints the JSON config snippet to paste into the right file. For Claude Code, copy the output into `.mcp.json` at your project root (or use the pre-wired `.mcp.json` already in this repo).
|
|
99
|
+
|
|
100
|
+
**Step 3 — Restart your AI tool**
|
|
101
|
+
|
|
102
|
+
The `agent-booster` MCP server will be available in every session. No further setup needed.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## CLI reference
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
booster index
|
|
110
|
+
```
|
|
111
|
+
Scans all `.py` files from the current directory, extracts functions and classes, stores in `.booster/symbols.db`. Skips `node_modules`, `.venv`, `__pycache__`, `.git`, `.booster`.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
booster search "<query>"
|
|
117
|
+
```
|
|
118
|
+
Keyword search across all indexed symbols. Returns file path, line number, kind, name, and signature.
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
booster search "workflow execute"
|
|
122
|
+
# apps/api/app/runtime/executor.py:1165 function _execute_output def _execute_output(...)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
booster serve
|
|
129
|
+
```
|
|
130
|
+
Starts the MCP server over stdio. Claude Code, Cursor, and Codex connect to this automatically when configured via `booster init`.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
booster init <platform>
|
|
136
|
+
```
|
|
137
|
+
Prints the MCP config snippet for the target platform. `platform` is one of: `claude`, `cursor`, `codex`, `all`.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
booster gain
|
|
143
|
+
```
|
|
144
|
+
Shows token savings statistics from past sessions. (Full analytics in a future release — currently a stub.)
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## MCP tools
|
|
149
|
+
|
|
150
|
+
Once `booster serve` is running, these tools are available to the agent:
|
|
151
|
+
|
|
152
|
+
### `get_symbols(file)`
|
|
153
|
+
Returns all indexed symbols for a file — name, kind, line range, and signature.
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
Input: { "file": "apps/api/app/runtime/executor.py" }
|
|
157
|
+
Output: function run_workflow (lines 42-89): def run_workflow(...)
|
|
158
|
+
class WorkflowState (lines 91-140): class WorkflowState:
|
|
159
|
+
...
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### `search_context(task)`
|
|
163
|
+
Keyword search across all symbols in the index. Returns top 10 matches with file locations.
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
Input: { "task": "authenticate user token" }
|
|
167
|
+
Output: apps/api/app/auth/middleware.py:34 function verify_token — def verify_token(...)
|
|
168
|
+
...
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### `smart_read(file, task)`
|
|
172
|
+
Returns only the lines of a file that are relevant to the task. Falls back to full file content if no symbols match.
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
Input: { "file": "apps/api/app/runtime/executor.py", "task": "execute output block" }
|
|
176
|
+
Output: # function _execute_output (lines 1165-1210)
|
|
177
|
+
def _execute_output(block, state, credentials, ...):
|
|
178
|
+
...
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## Platform config details
|
|
184
|
+
|
|
185
|
+
### Claude Code
|
|
186
|
+
|
|
187
|
+
Add to `.mcp.json` in your project root:
|
|
188
|
+
|
|
189
|
+
```json
|
|
190
|
+
{
|
|
191
|
+
"mcpServers": {
|
|
192
|
+
"agent-booster": {
|
|
193
|
+
"command": "booster",
|
|
194
|
+
"args": ["serve"]
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Cursor
|
|
201
|
+
|
|
202
|
+
Add to `.cursor/mcp.json`:
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"mcpServers": {
|
|
207
|
+
"agent-booster": {
|
|
208
|
+
"command": "booster",
|
|
209
|
+
"args": ["serve"]
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### OpenAI Codex CLI
|
|
216
|
+
|
|
217
|
+
Add to `~/.codex/config.json`:
|
|
218
|
+
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"mcp": {
|
|
222
|
+
"servers": {
|
|
223
|
+
"agent-booster": {
|
|
224
|
+
"command": "booster",
|
|
225
|
+
"args": ["serve"]
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## Where it fits
|
|
235
|
+
|
|
236
|
+
Agent Booster is the third layer in a three-layer token reduction stack — each layer is independent and addable separately:
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
Layer 3 — Agent Booster AST+semantic routing, smart file reads
|
|
240
|
+
Layer 2 — RTK Token compression on tool output
|
|
241
|
+
Layer 1 — Prompt caching Stable context reuse (native to Claude Code + API)
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Project layout
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
tools/booster/
|
|
250
|
+
├── README.md
|
|
251
|
+
├── pyproject.toml
|
|
252
|
+
└── booster/
|
|
253
|
+
├── __init__.py
|
|
254
|
+
├── cli.py # click commands: index, search, serve, init, gain
|
|
255
|
+
├── indexer.py # tree-sitter parser + SQLite symbol store
|
|
256
|
+
├── retriever.py # smart_read: task description → relevant line slice
|
|
257
|
+
└── mcp_server.py # MCP server exposing get_symbols, search_context, smart_read
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## Roadmap
|
|
263
|
+
|
|
264
|
+
- [ ] TypeScript/TSX support (tree-sitter-typescript)
|
|
265
|
+
- [ ] Vector embeddings for semantic (not just keyword) search
|
|
266
|
+
- [ ] Smart model routing (`route_model` tool: Haiku / Sonnet / Opus)
|
|
267
|
+
- [ ] `booster gain` — real token savings analytics
|
|
268
|
+
- [ ] Watch mode: auto re-index on file save
|
|
269
|
+
- [ ] Publish to PyPI as `agent-booster`
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
agent_booster.egg-info/PKG-INFO
|
|
5
|
+
agent_booster.egg-info/SOURCES.txt
|
|
6
|
+
agent_booster.egg-info/dependency_links.txt
|
|
7
|
+
agent_booster.egg-info/entry_points.txt
|
|
8
|
+
agent_booster.egg-info/requires.txt
|
|
9
|
+
agent_booster.egg-info/top_level.txt
|
|
10
|
+
booster/__init__.py
|
|
11
|
+
booster/cli.py
|
|
12
|
+
booster/indexer.py
|
|
13
|
+
booster/mcp_server.py
|
|
14
|
+
booster/retriever.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
booster
|
|
File without changes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import click
|
|
8
|
+
|
|
9
|
+
from booster.indexer import SymbolIndexer
|
|
10
|
+
|
|
11
|
+
_CLAUDE_SNIPPET = {
|
|
12
|
+
"mcpServers": {
|
|
13
|
+
"agent-booster": {
|
|
14
|
+
"command": "booster",
|
|
15
|
+
"args": ["serve"],
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
_CURSOR_SNIPPET = {
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"agent-booster": {
|
|
23
|
+
"command": "booster",
|
|
24
|
+
"args": ["serve"],
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
_CODEX_SNIPPET = {
|
|
30
|
+
"mcp": {
|
|
31
|
+
"servers": {
|
|
32
|
+
"agent-booster": {
|
|
33
|
+
"command": "booster",
|
|
34
|
+
"args": ["serve"],
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@click.group()
|
|
42
|
+
def main() -> None:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@main.command("index")
|
|
47
|
+
def cmd_index() -> None:
|
|
48
|
+
root = Path.cwd()
|
|
49
|
+
indexer = SymbolIndexer(root)
|
|
50
|
+
files, symbols = indexer.index_all()
|
|
51
|
+
click.echo(f"Indexed {files} files, {symbols} symbols.")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@main.command("search")
|
|
55
|
+
@click.argument("query")
|
|
56
|
+
def cmd_search(query: str) -> None:
|
|
57
|
+
root = Path.cwd()
|
|
58
|
+
indexer = SymbolIndexer(root)
|
|
59
|
+
results = indexer.search(query)
|
|
60
|
+
if not results:
|
|
61
|
+
click.echo("No matches.")
|
|
62
|
+
return
|
|
63
|
+
for r in results:
|
|
64
|
+
click.echo(f"{r['file']}:{r['start_line']} {r['kind']} {r['name']} {r['signature']}")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@main.command("serve")
|
|
68
|
+
def cmd_serve() -> None:
|
|
69
|
+
from booster.mcp_server import serve
|
|
70
|
+
asyncio.run(serve())
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@main.command("init")
|
|
74
|
+
@click.argument("platform", type=click.Choice(["claude", "cursor", "codex", "all"]))
|
|
75
|
+
def cmd_init(platform: str) -> None:
|
|
76
|
+
def _print(label: str, snippet: dict) -> None:
|
|
77
|
+
click.echo(f"# {label}")
|
|
78
|
+
click.echo(json.dumps(snippet, indent=2))
|
|
79
|
+
click.echo()
|
|
80
|
+
|
|
81
|
+
if platform in ("claude", "all"):
|
|
82
|
+
_print("Add to .mcp.json (project root)", _CLAUDE_SNIPPET)
|
|
83
|
+
if platform in ("cursor", "all"):
|
|
84
|
+
_print("Add to .cursor/mcp.json", _CURSOR_SNIPPET)
|
|
85
|
+
if platform in ("codex", "all"):
|
|
86
|
+
_print("Add to ~/.codex/config.json", _CODEX_SNIPPET)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
@main.command("gain")
|
|
90
|
+
def cmd_gain() -> None:
|
|
91
|
+
click.echo("No stats yet. Run some sessions first.")
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sqlite3
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import tree_sitter_python as tspython
|
|
7
|
+
from tree_sitter import Language, Node, Parser
|
|
8
|
+
|
|
9
|
+
PY_LANGUAGE = Language(tspython.language())
|
|
10
|
+
|
|
11
|
+
_SKIP_DIRS = {"node_modules", ".venv", "__pycache__", ".git", ".booster"}
|
|
12
|
+
|
|
13
|
+
_CREATE_TABLE = """
|
|
14
|
+
CREATE TABLE IF NOT EXISTS symbols (
|
|
15
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
16
|
+
file TEXT NOT NULL,
|
|
17
|
+
name TEXT NOT NULL,
|
|
18
|
+
kind TEXT NOT NULL,
|
|
19
|
+
start_line INTEGER NOT NULL,
|
|
20
|
+
end_line INTEGER NOT NULL,
|
|
21
|
+
signature TEXT NOT NULL DEFAULT ''
|
|
22
|
+
)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
_KIND_MAP = {
|
|
26
|
+
"function_definition": "function",
|
|
27
|
+
"class_definition": "class",
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _extract_name(node: Node, source: bytes) -> str:
|
|
32
|
+
for child in node.children:
|
|
33
|
+
if child.type == "identifier":
|
|
34
|
+
return source[child.start_byte:child.end_byte].decode("utf-8", errors="replace")
|
|
35
|
+
return ""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _extract_signature(node: Node, source: bytes) -> str:
|
|
39
|
+
first_line_end = source.find(b"\n", node.start_byte)
|
|
40
|
+
if first_line_end == -1:
|
|
41
|
+
first_line_end = node.end_byte
|
|
42
|
+
return source[node.start_byte:first_line_end].decode("utf-8", errors="replace").strip()
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class SymbolIndexer:
|
|
46
|
+
def __init__(self, root: Path) -> None:
|
|
47
|
+
self.root = root
|
|
48
|
+
db_dir = root / ".booster"
|
|
49
|
+
db_dir.mkdir(exist_ok=True)
|
|
50
|
+
self._conn = sqlite3.connect(str(db_dir / "symbols.db"))
|
|
51
|
+
self._conn.row_factory = sqlite3.Row
|
|
52
|
+
self._conn.execute(_CREATE_TABLE)
|
|
53
|
+
self._conn.commit()
|
|
54
|
+
self._parser = Parser(PY_LANGUAGE)
|
|
55
|
+
|
|
56
|
+
def index_file(self, path: Path) -> int:
|
|
57
|
+
source = path.read_bytes()
|
|
58
|
+
tree = self._parser.parse(source)
|
|
59
|
+
rel = str(path.relative_to(self.root))
|
|
60
|
+
|
|
61
|
+
self._conn.execute("DELETE FROM symbols WHERE file = ?", (rel,))
|
|
62
|
+
|
|
63
|
+
inserted = 0
|
|
64
|
+
cursor = [tree.root_node]
|
|
65
|
+
while cursor:
|
|
66
|
+
node = cursor.pop()
|
|
67
|
+
if node.type in _KIND_MAP:
|
|
68
|
+
name = _extract_name(node, source)
|
|
69
|
+
if name:
|
|
70
|
+
sig = _extract_signature(node, source)
|
|
71
|
+
self._conn.execute(
|
|
72
|
+
"INSERT INTO symbols (file, name, kind, start_line, end_line, signature) VALUES (?, ?, ?, ?, ?, ?)",
|
|
73
|
+
(rel, name, _KIND_MAP[node.type], node.start_point[0] + 1, node.end_point[0] + 1, sig),
|
|
74
|
+
)
|
|
75
|
+
inserted += 1
|
|
76
|
+
cursor.extend(node.children)
|
|
77
|
+
|
|
78
|
+
self._conn.commit()
|
|
79
|
+
return inserted
|
|
80
|
+
|
|
81
|
+
def index_all(self) -> tuple[int, int]:
|
|
82
|
+
files = 0
|
|
83
|
+
symbols = 0
|
|
84
|
+
for path in self.root.rglob("*.py"):
|
|
85
|
+
if any(part in _SKIP_DIRS for part in path.parts):
|
|
86
|
+
continue
|
|
87
|
+
try:
|
|
88
|
+
symbols += self.index_file(path)
|
|
89
|
+
files += 1
|
|
90
|
+
except Exception:
|
|
91
|
+
pass
|
|
92
|
+
return files, symbols
|
|
93
|
+
|
|
94
|
+
def get_symbols(self, file: str) -> list[dict]:
|
|
95
|
+
rows = self._conn.execute(
|
|
96
|
+
"SELECT * FROM symbols WHERE file = ? ORDER BY start_line", (file,)
|
|
97
|
+
).fetchall()
|
|
98
|
+
return [dict(r) for r in rows]
|
|
99
|
+
|
|
100
|
+
def search(self, query: str, limit: int = 10) -> list[dict]:
|
|
101
|
+
terms = query.lower().split()
|
|
102
|
+
if not terms:
|
|
103
|
+
return []
|
|
104
|
+
conditions = " AND ".join(
|
|
105
|
+
"(LOWER(name) LIKE ? OR LOWER(signature) LIKE ?)" for _ in terms
|
|
106
|
+
)
|
|
107
|
+
params: list[str] = []
|
|
108
|
+
for t in terms:
|
|
109
|
+
params.extend([f"%{t}%", f"%{t}%"])
|
|
110
|
+
params.append(str(limit))
|
|
111
|
+
rows = self._conn.execute(
|
|
112
|
+
f"SELECT * FROM symbols WHERE {conditions} ORDER BY name LIMIT ?",
|
|
113
|
+
params,
|
|
114
|
+
).fetchall()
|
|
115
|
+
return [dict(r) for r in rows]
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from mcp.server import Server
|
|
6
|
+
from mcp.server.stdio import stdio_server
|
|
7
|
+
from mcp.types import TextContent, Tool
|
|
8
|
+
|
|
9
|
+
from booster.indexer import SymbolIndexer
|
|
10
|
+
from booster.retriever import smart_read as _smart_read
|
|
11
|
+
|
|
12
|
+
_ROOT = Path.cwd()
|
|
13
|
+
_indexer: SymbolIndexer | None = None
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _get_indexer() -> SymbolIndexer:
|
|
17
|
+
global _indexer
|
|
18
|
+
if _indexer is None:
|
|
19
|
+
_indexer = SymbolIndexer(_ROOT)
|
|
20
|
+
return _indexer
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
app = Server("agent-booster")
|
|
24
|
+
app.version = "0.1.0"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.list_tools()
|
|
28
|
+
async def list_tools() -> list[Tool]:
|
|
29
|
+
return [
|
|
30
|
+
Tool(
|
|
31
|
+
name="get_symbols",
|
|
32
|
+
description="Return all indexed symbols for a given file path.",
|
|
33
|
+
inputSchema={
|
|
34
|
+
"type": "object",
|
|
35
|
+
"properties": {"file": {"type": "string", "description": "Relative file path"}},
|
|
36
|
+
"required": ["file"],
|
|
37
|
+
},
|
|
38
|
+
),
|
|
39
|
+
Tool(
|
|
40
|
+
name="search_context",
|
|
41
|
+
description="Keyword search across all indexed symbols. Returns top 10 matches.",
|
|
42
|
+
inputSchema={
|
|
43
|
+
"type": "object",
|
|
44
|
+
"properties": {"task": {"type": "string", "description": "Task description or keywords"}},
|
|
45
|
+
"required": ["task"],
|
|
46
|
+
},
|
|
47
|
+
),
|
|
48
|
+
Tool(
|
|
49
|
+
name="smart_read",
|
|
50
|
+
description="Return only the relevant slice of a file based on a task description.",
|
|
51
|
+
inputSchema={
|
|
52
|
+
"type": "object",
|
|
53
|
+
"properties": {
|
|
54
|
+
"file": {"type": "string", "description": "Relative file path"},
|
|
55
|
+
"task": {"type": "string", "description": "Task description"},
|
|
56
|
+
},
|
|
57
|
+
"required": ["file", "task"],
|
|
58
|
+
},
|
|
59
|
+
),
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@app.call_tool()
|
|
64
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
65
|
+
indexer = _get_indexer()
|
|
66
|
+
|
|
67
|
+
if name == "get_symbols":
|
|
68
|
+
symbols = indexer.get_symbols(arguments["file"])
|
|
69
|
+
lines = [
|
|
70
|
+
f"{s['kind']} {s['name']} (lines {s['start_line']}-{s['end_line']}): {s['signature']}"
|
|
71
|
+
for s in symbols
|
|
72
|
+
]
|
|
73
|
+
text = "\n".join(lines) if lines else "No symbols found."
|
|
74
|
+
return [TextContent(type="text", text=text)]
|
|
75
|
+
|
|
76
|
+
if name == "search_context":
|
|
77
|
+
results = indexer.search(arguments["task"], limit=10)
|
|
78
|
+
lines = [
|
|
79
|
+
f"{s['file']}:{s['start_line']} {s['kind']} {s['name']} — {s['signature']}"
|
|
80
|
+
for s in results
|
|
81
|
+
]
|
|
82
|
+
text = "\n".join(lines) if lines else "No matches found."
|
|
83
|
+
return [TextContent(type="text", text=text)]
|
|
84
|
+
|
|
85
|
+
if name == "smart_read":
|
|
86
|
+
file_path = _ROOT / arguments["file"]
|
|
87
|
+
text = _smart_read(file_path, arguments["task"], indexer)
|
|
88
|
+
return [TextContent(type="text", text=text)]
|
|
89
|
+
|
|
90
|
+
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
async def serve() -> None:
|
|
94
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
95
|
+
await app.run(read_stream, write_stream, app.create_initialization_options())
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
from booster.indexer import SymbolIndexer
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def smart_read(file_path: Path, task: str, indexer: SymbolIndexer) -> str:
|
|
9
|
+
rel = str(file_path.relative_to(indexer.root))
|
|
10
|
+
keywords = [w.lower() for w in task.split() if len(w) > 2]
|
|
11
|
+
|
|
12
|
+
all_symbols = indexer.get_symbols(rel)
|
|
13
|
+
matched = [
|
|
14
|
+
s for s in all_symbols
|
|
15
|
+
if any(kw in s["name"].lower() or kw in s["signature"].lower() for kw in keywords)
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
source_lines = file_path.read_text(encoding="utf-8", errors="replace").splitlines()
|
|
19
|
+
|
|
20
|
+
if not matched:
|
|
21
|
+
return "\n".join(source_lines)
|
|
22
|
+
|
|
23
|
+
chunks: list[str] = []
|
|
24
|
+
for sym in matched:
|
|
25
|
+
start = sym["start_line"] - 1
|
|
26
|
+
end = sym["end_line"]
|
|
27
|
+
header = f"# {sym['kind']} {sym['name']} (lines {sym['start_line']}-{sym['end_line']})"
|
|
28
|
+
body = "\n".join(source_lines[start:end])
|
|
29
|
+
chunks.append(f"{header}\n{body}")
|
|
30
|
+
|
|
31
|
+
return "\n\n".join(chunks)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agent-booster"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "AST+vector context router for AI coding agents — cut token costs 5-15x"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
authors = [{ name = "Sudhi Seshachala", email = "Sudhi@b2bsphere.com" }]
|
|
13
|
+
keywords = ["ai", "llm", "claude", "cursor", "codex", "mcp", "tokens", "ast"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
23
|
+
]
|
|
24
|
+
dependencies = [
|
|
25
|
+
"tree-sitter>=0.23",
|
|
26
|
+
"tree-sitter-python>=0.23",
|
|
27
|
+
"tree-sitter-typescript>=0.23",
|
|
28
|
+
"click>=8.1",
|
|
29
|
+
"mcp>=1.0",
|
|
30
|
+
"numpy>=1.26",
|
|
31
|
+
"anthropic>=0.40",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.urls]
|
|
35
|
+
Homepage = "https://github.com/sseshachala/conductai"
|
|
36
|
+
Repository = "https://github.com/sseshachala/conductai"
|
|
37
|
+
Issues = "https://github.com/sseshachala/conductai/issues"
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
booster = "booster.cli:main"
|
|
41
|
+
|
|
42
|
+
[tool.setuptools.packages.find]
|
|
43
|
+
where = ["."]
|
|
44
|
+
include = ["booster*"]
|