claude-contextmesh 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.
- claude_contextmesh-0.1.0/.gitignore +6 -0
- claude_contextmesh-0.1.0/CLAUDE.md +18 -0
- claude_contextmesh-0.1.0/LICENSE +21 -0
- claude_contextmesh-0.1.0/PKG-INFO +222 -0
- claude_contextmesh-0.1.0/README.md +189 -0
- claude_contextmesh-0.1.0/pyproject.toml +78 -0
- claude_contextmesh-0.1.0/scripts/hook_event.sh +34 -0
- claude_contextmesh-0.1.0/scripts/install.sh +109 -0
- claude_contextmesh-0.1.0/src/contextmesh/__init__.py +4 -0
- claude_contextmesh-0.1.0/src/contextmesh/bootstrap.py +110 -0
- claude_contextmesh-0.1.0/src/contextmesh/cli.py +290 -0
- claude_contextmesh-0.1.0/src/contextmesh/config.py +199 -0
- claude_contextmesh-0.1.0/src/contextmesh/daemon/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/daemon/handlers.py +375 -0
- claude_contextmesh-0.1.0/src/contextmesh/daemon/server.py +252 -0
- claude_contextmesh-0.1.0/src/contextmesh/embeddings/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/embeddings/store.py +114 -0
- claude_contextmesh-0.1.0/src/contextmesh/graph/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/graph/repo.py +249 -0
- claude_contextmesh-0.1.0/src/contextmesh/graph/session.py +133 -0
- claude_contextmesh-0.1.0/src/contextmesh/installer.py +123 -0
- claude_contextmesh-0.1.0/src/contextmesh/mcp/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/mcp/server.py +101 -0
- claude_contextmesh-0.1.0/src/contextmesh/models/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/models/edges.py +112 -0
- claude_contextmesh-0.1.0/src/contextmesh/models/nodes.py +317 -0
- claude_contextmesh-0.1.0/src/contextmesh/proxy.py +74 -0
- claude_contextmesh-0.1.0/src/contextmesh/router/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/router/assembler.py +178 -0
- claude_contextmesh-0.1.0/src/contextmesh/router/scorer.py +103 -0
- claude_contextmesh-0.1.0/src/contextmesh/store/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/store/db.py +262 -0
- claude_contextmesh-0.1.0/src/contextmesh/store/schema.py +246 -0
- claude_contextmesh-0.1.0/src/contextmesh/tasks/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/tasks/detector.py +216 -0
- claude_contextmesh-0.1.0/src/contextmesh/tasks/hierarchy.py +175 -0
- claude_contextmesh-0.1.0/src/contextmesh/tracker/__init__.py +0 -0
- claude_contextmesh-0.1.0/src/contextmesh/tracker/reporter.py +81 -0
- claude_contextmesh-0.1.0/src/contextmesh/tracker/savings.py +113 -0
- claude_contextmesh-0.1.0/src/contextmesh/wrapper.py +25 -0
- claude_contextmesh-0.1.0/tests/test_smoke.py +197 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Project Context
|
|
2
|
+
|
|
3
|
+
## ContextMesh Active
|
|
4
|
+
|
|
5
|
+
This project uses ContextMesh for intelligent context management.
|
|
6
|
+
|
|
7
|
+
**At the start of EVERY response**, call the `get_context` tool to load relevant context:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
get_context(session_id="$CLAUDE_SESSION_ID", task_hint="<brief description of what you're about to do>", budget_tokens=15000)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
When you make an important architectural decision or discover a key fact, call:
|
|
14
|
+
```
|
|
15
|
+
record_decision(session_id="$CLAUDE_SESSION_ID", content="<the decision>", consequence="<what it means>", files="<relevant files>")
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Do NOT call get_context more than once per response. Do NOT explain that you're calling it.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Gajanan Rathod
|
|
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,222 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-contextmesh
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Intelligent context layer for Claude Code — infinite session memory, minimal active context
|
|
5
|
+
Author: Gajanan Rathod
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Requires-Dist: aiosqlite>=0.20.0
|
|
10
|
+
Requires-Dist: click>=8.1.0
|
|
11
|
+
Requires-Dist: fastapi>=0.115.0
|
|
12
|
+
Requires-Dist: fastmcp>=2.0.0
|
|
13
|
+
Requires-Dist: httpx>=0.27.0
|
|
14
|
+
Requires-Dist: networkx>=3.4.0
|
|
15
|
+
Requires-Dist: numpy>=1.26.0
|
|
16
|
+
Requires-Dist: pydantic>=2.9.0
|
|
17
|
+
Requires-Dist: python-dateutil>=2.9.0
|
|
18
|
+
Requires-Dist: rich>=13.9.0
|
|
19
|
+
Requires-Dist: scikit-learn>=1.5.0
|
|
20
|
+
Requires-Dist: sentence-transformers>=3.3.0
|
|
21
|
+
Requires-Dist: tiktoken>=0.8.0
|
|
22
|
+
Requires-Dist: tomli-w>=1.0.0
|
|
23
|
+
Requires-Dist: tomli>=2.0.0; python_version < '3.11'
|
|
24
|
+
Requires-Dist: tree-sitter-language-pack>=0.7.0
|
|
25
|
+
Requires-Dist: tree-sitter>=0.23.0
|
|
26
|
+
Requires-Dist: uvicorn[standard]>=0.32.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: mypy>=1.13.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: pytest>=8.3.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.7.0; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# ContextMesh — Intelligent Context Layer for Claude Code
|
|
35
|
+
|
|
36
|
+
> One coding session. Infinite memory. Minimal active context.
|
|
37
|
+
|
|
38
|
+
ContextMesh sits between Claude Code and the model. It captures every event in your session, builds a structured knowledge graph of your work, and dynamically provides Claude with only the most relevant context for the current task — saving tokens, reducing cost, and preventing context overload.
|
|
39
|
+
|
|
40
|
+
## How it works
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
Claude Code Hooks → ContextMesh Daemon → Session Graph + Repo Graph
|
|
44
|
+
↓
|
|
45
|
+
Context Router (multi-signal scoring)
|
|
46
|
+
↓
|
|
47
|
+
Claude Code ← MCP Server (get_context)
|
|
48
|
+
↓
|
|
49
|
+
Token Savings Tracker → Report
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**The key insight**: semantic similarity alone fails for long coding sessions because everything related to the same feature looks similar. ContextMesh uses graph proximity + code dependency relationships + causal edges + recency + file overlap — not just vectors.
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Clone and install
|
|
58
|
+
git clone https://github.com/you/ContextMesh
|
|
59
|
+
cd ContextMesh
|
|
60
|
+
pip install -e .
|
|
61
|
+
|
|
62
|
+
# Run the install script (sets up hooks + config)
|
|
63
|
+
bash scripts/install.sh
|
|
64
|
+
|
|
65
|
+
# Index your project's codebase
|
|
66
|
+
contextmesh index /path/to/your/project
|
|
67
|
+
|
|
68
|
+
# Start the daemon
|
|
69
|
+
contextmesh start
|
|
70
|
+
|
|
71
|
+
# Start the MCP server (in a separate terminal)
|
|
72
|
+
contextmesh mcp
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### For exact token measurement (Claude Enterprise)
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# Start the token proxy
|
|
79
|
+
contextmesh proxy
|
|
80
|
+
|
|
81
|
+
# Then set in your environment:
|
|
82
|
+
export ANTHROPIC_BASE_URL=http://localhost:8099
|
|
83
|
+
|
|
84
|
+
# This records EXACT token counts from actual API responses
|
|
85
|
+
# including cache_creation_input_tokens and cache_read_input_tokens
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Adding ContextMesh to a project
|
|
89
|
+
|
|
90
|
+
Copy `CLAUDE.md` from this repo to your project root. Claude Code will automatically instruct Claude to use the `get_context` tool at the start of each response.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
cp /path/to/ContextMesh/CLAUDE.md /path/to/your/project/CLAUDE.md
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Register MCP server with Claude Code
|
|
97
|
+
|
|
98
|
+
Add to `~/.claude/settings.json`:
|
|
99
|
+
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"mcpServers": {
|
|
103
|
+
"contextmesh": {
|
|
104
|
+
"command": "contextmesh",
|
|
105
|
+
"args": ["mcp"]
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## View token savings
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Session summary
|
|
115
|
+
contextmesh stats --session YOUR_SESSION_ID
|
|
116
|
+
|
|
117
|
+
# Recent turns with savings breakdown
|
|
118
|
+
contextmesh turns --session YOUR_SESSION_ID --limit 20
|
|
119
|
+
|
|
120
|
+
# Global summary across all sessions
|
|
121
|
+
contextmesh stats
|
|
122
|
+
|
|
123
|
+
# If using proxy mode — actual API token counts
|
|
124
|
+
contextmesh stats --proxy
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Token savings tracker
|
|
128
|
+
|
|
129
|
+
Every time Claude calls `get_context()`, ContextMesh records:
|
|
130
|
+
|
|
131
|
+
| Metric | What it is |
|
|
132
|
+
|--------|-----------|
|
|
133
|
+
| **Accumulated tokens** | What the full session history would have been |
|
|
134
|
+
| **Routed tokens** | What ContextMesh actually provided |
|
|
135
|
+
| **Tokens saved** | The difference |
|
|
136
|
+
| **Compression ratio** | routed / accumulated |
|
|
137
|
+
| **Cost saved** | Based on your configured per-MTok price |
|
|
138
|
+
|
|
139
|
+
## Architecture
|
|
140
|
+
|
|
141
|
+
### Dual Graph
|
|
142
|
+
|
|
143
|
+
**Session Graph** — captures every meaningful event:
|
|
144
|
+
- User prompts, tool results, file reads/writes
|
|
145
|
+
- Decisions, bugs, solutions, errors, test results
|
|
146
|
+
- Typed edges: `caused_by`, `solved_by`, `depends_on`, `same_task`
|
|
147
|
+
|
|
148
|
+
**Repo Graph** — deterministic code relationships:
|
|
149
|
+
- Functions, classes, methods, files (Tree-sitter parsed)
|
|
150
|
+
- `calls`, `imports`, `same_file`, `tested_by`, `inherits` edges
|
|
151
|
+
- Updated incrementally on every file write
|
|
152
|
+
|
|
153
|
+
### Hot / Warm / Cold Memory
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
HOT → Current task context (always injected)
|
|
157
|
+
WARM → Related tasks, decisions, nearby graph nodes (retrieved on demand)
|
|
158
|
+
COLD → Full historical transcripts (never auto-injected)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### Context Router
|
|
162
|
+
|
|
163
|
+
Before every `get_context()` call:
|
|
164
|
+
|
|
165
|
+
```
|
|
166
|
+
context_score =
|
|
167
|
+
semantic_relevance (embedding cosine similarity)
|
|
168
|
+
+ graph_proximity (BFS distance in session graph)
|
|
169
|
+
+ file_overlap (Jaccard similarity with current task files)
|
|
170
|
+
+ recency (exponential decay from now)
|
|
171
|
+
+ causal_relevance (DECISION/BUG/SOLUTION type bonus)
|
|
172
|
+
+ unresolved_bonus (UNRESOLVED_ISSUE always surfaces)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Cache-aware assembly order
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
STATIC (cacheable)
|
|
179
|
+
─────────────────────────────
|
|
180
|
+
=== CURRENT TASK ===
|
|
181
|
+
[hot nodes — current thread]
|
|
182
|
+
|
|
183
|
+
=== RELEVANT DECISIONS ===
|
|
184
|
+
[top-scored decisions]
|
|
185
|
+
|
|
186
|
+
DYNAMIC
|
|
187
|
+
─────────────────────────────
|
|
188
|
+
=== RELATED CODE CONTEXT ===
|
|
189
|
+
[repo graph: functions/classes in touched files]
|
|
190
|
+
|
|
191
|
+
=== RECENT HISTORY ===
|
|
192
|
+
[recent warm nodes]
|
|
193
|
+
|
|
194
|
+
=== UNRESOLVED ISSUES ===
|
|
195
|
+
[always surfaced]
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Configuration
|
|
199
|
+
|
|
200
|
+
`.contextmesh/config.toml` in your project (or `~/.contextmesh/config.toml` globally):
|
|
201
|
+
|
|
202
|
+
```toml
|
|
203
|
+
[router]
|
|
204
|
+
default_budget_tokens = 15000
|
|
205
|
+
|
|
206
|
+
[tracker]
|
|
207
|
+
input_price_per_mtok = 3.0 # Claude Enterprise cached input price
|
|
208
|
+
uncached_price_per_mtok = 15.0
|
|
209
|
+
|
|
210
|
+
[embeddings]
|
|
211
|
+
model = "all-MiniLM-L6-v2" # Local, no API key needed
|
|
212
|
+
|
|
213
|
+
[tasks]
|
|
214
|
+
topic_shift_threshold = 0.35 # Cosine distance to detect task switch
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
pip install -e ".[dev]"
|
|
221
|
+
pytest tests/
|
|
222
|
+
```
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# ContextMesh — Intelligent Context Layer for Claude Code
|
|
2
|
+
|
|
3
|
+
> One coding session. Infinite memory. Minimal active context.
|
|
4
|
+
|
|
5
|
+
ContextMesh sits between Claude Code and the model. It captures every event in your session, builds a structured knowledge graph of your work, and dynamically provides Claude with only the most relevant context for the current task — saving tokens, reducing cost, and preventing context overload.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
Claude Code Hooks → ContextMesh Daemon → Session Graph + Repo Graph
|
|
11
|
+
↓
|
|
12
|
+
Context Router (multi-signal scoring)
|
|
13
|
+
↓
|
|
14
|
+
Claude Code ← MCP Server (get_context)
|
|
15
|
+
↓
|
|
16
|
+
Token Savings Tracker → Report
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**The key insight**: semantic similarity alone fails for long coding sessions because everything related to the same feature looks similar. ContextMesh uses graph proximity + code dependency relationships + causal edges + recency + file overlap — not just vectors.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
# Clone and install
|
|
25
|
+
git clone https://github.com/you/ContextMesh
|
|
26
|
+
cd ContextMesh
|
|
27
|
+
pip install -e .
|
|
28
|
+
|
|
29
|
+
# Run the install script (sets up hooks + config)
|
|
30
|
+
bash scripts/install.sh
|
|
31
|
+
|
|
32
|
+
# Index your project's codebase
|
|
33
|
+
contextmesh index /path/to/your/project
|
|
34
|
+
|
|
35
|
+
# Start the daemon
|
|
36
|
+
contextmesh start
|
|
37
|
+
|
|
38
|
+
# Start the MCP server (in a separate terminal)
|
|
39
|
+
contextmesh mcp
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### For exact token measurement (Claude Enterprise)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Start the token proxy
|
|
46
|
+
contextmesh proxy
|
|
47
|
+
|
|
48
|
+
# Then set in your environment:
|
|
49
|
+
export ANTHROPIC_BASE_URL=http://localhost:8099
|
|
50
|
+
|
|
51
|
+
# This records EXACT token counts from actual API responses
|
|
52
|
+
# including cache_creation_input_tokens and cache_read_input_tokens
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Adding ContextMesh to a project
|
|
56
|
+
|
|
57
|
+
Copy `CLAUDE.md` from this repo to your project root. Claude Code will automatically instruct Claude to use the `get_context` tool at the start of each response.
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cp /path/to/ContextMesh/CLAUDE.md /path/to/your/project/CLAUDE.md
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Register MCP server with Claude Code
|
|
64
|
+
|
|
65
|
+
Add to `~/.claude/settings.json`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"contextmesh": {
|
|
71
|
+
"command": "contextmesh",
|
|
72
|
+
"args": ["mcp"]
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## View token savings
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Session summary
|
|
82
|
+
contextmesh stats --session YOUR_SESSION_ID
|
|
83
|
+
|
|
84
|
+
# Recent turns with savings breakdown
|
|
85
|
+
contextmesh turns --session YOUR_SESSION_ID --limit 20
|
|
86
|
+
|
|
87
|
+
# Global summary across all sessions
|
|
88
|
+
contextmesh stats
|
|
89
|
+
|
|
90
|
+
# If using proxy mode — actual API token counts
|
|
91
|
+
contextmesh stats --proxy
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Token savings tracker
|
|
95
|
+
|
|
96
|
+
Every time Claude calls `get_context()`, ContextMesh records:
|
|
97
|
+
|
|
98
|
+
| Metric | What it is |
|
|
99
|
+
|--------|-----------|
|
|
100
|
+
| **Accumulated tokens** | What the full session history would have been |
|
|
101
|
+
| **Routed tokens** | What ContextMesh actually provided |
|
|
102
|
+
| **Tokens saved** | The difference |
|
|
103
|
+
| **Compression ratio** | routed / accumulated |
|
|
104
|
+
| **Cost saved** | Based on your configured per-MTok price |
|
|
105
|
+
|
|
106
|
+
## Architecture
|
|
107
|
+
|
|
108
|
+
### Dual Graph
|
|
109
|
+
|
|
110
|
+
**Session Graph** — captures every meaningful event:
|
|
111
|
+
- User prompts, tool results, file reads/writes
|
|
112
|
+
- Decisions, bugs, solutions, errors, test results
|
|
113
|
+
- Typed edges: `caused_by`, `solved_by`, `depends_on`, `same_task`
|
|
114
|
+
|
|
115
|
+
**Repo Graph** — deterministic code relationships:
|
|
116
|
+
- Functions, classes, methods, files (Tree-sitter parsed)
|
|
117
|
+
- `calls`, `imports`, `same_file`, `tested_by`, `inherits` edges
|
|
118
|
+
- Updated incrementally on every file write
|
|
119
|
+
|
|
120
|
+
### Hot / Warm / Cold Memory
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
HOT → Current task context (always injected)
|
|
124
|
+
WARM → Related tasks, decisions, nearby graph nodes (retrieved on demand)
|
|
125
|
+
COLD → Full historical transcripts (never auto-injected)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Context Router
|
|
129
|
+
|
|
130
|
+
Before every `get_context()` call:
|
|
131
|
+
|
|
132
|
+
```
|
|
133
|
+
context_score =
|
|
134
|
+
semantic_relevance (embedding cosine similarity)
|
|
135
|
+
+ graph_proximity (BFS distance in session graph)
|
|
136
|
+
+ file_overlap (Jaccard similarity with current task files)
|
|
137
|
+
+ recency (exponential decay from now)
|
|
138
|
+
+ causal_relevance (DECISION/BUG/SOLUTION type bonus)
|
|
139
|
+
+ unresolved_bonus (UNRESOLVED_ISSUE always surfaces)
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Cache-aware assembly order
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
STATIC (cacheable)
|
|
146
|
+
─────────────────────────────
|
|
147
|
+
=== CURRENT TASK ===
|
|
148
|
+
[hot nodes — current thread]
|
|
149
|
+
|
|
150
|
+
=== RELEVANT DECISIONS ===
|
|
151
|
+
[top-scored decisions]
|
|
152
|
+
|
|
153
|
+
DYNAMIC
|
|
154
|
+
─────────────────────────────
|
|
155
|
+
=== RELATED CODE CONTEXT ===
|
|
156
|
+
[repo graph: functions/classes in touched files]
|
|
157
|
+
|
|
158
|
+
=== RECENT HISTORY ===
|
|
159
|
+
[recent warm nodes]
|
|
160
|
+
|
|
161
|
+
=== UNRESOLVED ISSUES ===
|
|
162
|
+
[always surfaced]
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Configuration
|
|
166
|
+
|
|
167
|
+
`.contextmesh/config.toml` in your project (or `~/.contextmesh/config.toml` globally):
|
|
168
|
+
|
|
169
|
+
```toml
|
|
170
|
+
[router]
|
|
171
|
+
default_budget_tokens = 15000
|
|
172
|
+
|
|
173
|
+
[tracker]
|
|
174
|
+
input_price_per_mtok = 3.0 # Claude Enterprise cached input price
|
|
175
|
+
uncached_price_per_mtok = 15.0
|
|
176
|
+
|
|
177
|
+
[embeddings]
|
|
178
|
+
model = "all-MiniLM-L6-v2" # Local, no API key needed
|
|
179
|
+
|
|
180
|
+
[tasks]
|
|
181
|
+
topic_shift_threshold = 0.35 # Cosine distance to detect task switch
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## Development
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install -e ".[dev]"
|
|
188
|
+
pytest tests/
|
|
189
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "claude-contextmesh"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Intelligent context layer for Claude Code — infinite session memory, minimal active context"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.11"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Gajanan Rathod" }]
|
|
13
|
+
|
|
14
|
+
dependencies = [
|
|
15
|
+
# Web framework & async
|
|
16
|
+
"fastapi>=0.115.0",
|
|
17
|
+
"uvicorn[standard]>=0.32.0",
|
|
18
|
+
"httpx>=0.27.0",
|
|
19
|
+
|
|
20
|
+
# Async SQLite
|
|
21
|
+
"aiosqlite>=0.20.0",
|
|
22
|
+
|
|
23
|
+
# Graph
|
|
24
|
+
"networkx>=3.4.0",
|
|
25
|
+
|
|
26
|
+
# Code parsing (Tree-sitter)
|
|
27
|
+
"tree-sitter>=0.23.0",
|
|
28
|
+
"tree-sitter-language-pack>=0.7.0",
|
|
29
|
+
|
|
30
|
+
# Embeddings (local, no external API)
|
|
31
|
+
"sentence-transformers>=3.3.0",
|
|
32
|
+
"numpy>=1.26.0",
|
|
33
|
+
|
|
34
|
+
# Token counting
|
|
35
|
+
"tiktoken>=0.8.0",
|
|
36
|
+
|
|
37
|
+
# MCP server
|
|
38
|
+
"fastmcp>=2.0.0",
|
|
39
|
+
|
|
40
|
+
# Data models
|
|
41
|
+
"pydantic>=2.9.0",
|
|
42
|
+
|
|
43
|
+
# Config
|
|
44
|
+
"tomli>=2.0.0; python_version < '3.11'",
|
|
45
|
+
"tomli-w>=1.0.0",
|
|
46
|
+
|
|
47
|
+
# CLI & display
|
|
48
|
+
"rich>=13.9.0",
|
|
49
|
+
"click>=8.1.0",
|
|
50
|
+
|
|
51
|
+
# Utilities
|
|
52
|
+
"scikit-learn>=1.5.0",
|
|
53
|
+
"python-dateutil>=2.9.0",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.optional-dependencies]
|
|
57
|
+
dev = [
|
|
58
|
+
"pytest>=8.3.0",
|
|
59
|
+
"pytest-asyncio>=0.24.0",
|
|
60
|
+
"ruff>=0.7.0",
|
|
61
|
+
"mypy>=1.13.0",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[project.scripts]
|
|
65
|
+
contextmesh = "contextmesh.cli:main"
|
|
66
|
+
claude-mesh = "contextmesh.wrapper:main"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
[tool.hatch.build.targets.wheel]
|
|
70
|
+
packages = ["src/contextmesh"]
|
|
71
|
+
|
|
72
|
+
[tool.ruff]
|
|
73
|
+
line-length = 100
|
|
74
|
+
target-version = "py311"
|
|
75
|
+
|
|
76
|
+
[tool.pytest.ini_options]
|
|
77
|
+
asyncio_mode = "auto"
|
|
78
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# ContextMesh hook relay script
|
|
3
|
+
# Called by Claude Code hooks. Reads JSON payload from stdin, POSTs to daemon.
|
|
4
|
+
# Usage: echo '{...}' | CONTEXTMESH_EVENT_TYPE=PostToolUse ./scripts/hook_event.sh
|
|
5
|
+
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
DAEMON_URL="${CONTEXTMESH_DAEMON_URL:-http://127.0.0.1:8765}"
|
|
9
|
+
EVENT_TYPE="${CONTEXTMESH_EVENT_TYPE:-Unknown}"
|
|
10
|
+
SESSION_ID="${CLAUDE_SESSION_ID:-unknown}"
|
|
11
|
+
PROJECT_PATH="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
12
|
+
|
|
13
|
+
# Read the hook payload from stdin
|
|
14
|
+
PAYLOAD=$(cat)
|
|
15
|
+
|
|
16
|
+
# Merge with our envelope fields
|
|
17
|
+
FULL_PAYLOAD=$(jq -n \
|
|
18
|
+
--arg event_type "$EVENT_TYPE" \
|
|
19
|
+
--arg session_id "$SESSION_ID" \
|
|
20
|
+
--arg project_path "$PROJECT_PATH" \
|
|
21
|
+
--argjson payload "$PAYLOAD" \
|
|
22
|
+
'($payload) + {event_type: $event_type, session_id: $session_id, project_path: $project_path}'
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# Fire and forget — don't block Claude Code
|
|
26
|
+
curl -s -f -X POST \
|
|
27
|
+
"${DAEMON_URL}/hook" \
|
|
28
|
+
-H 'Content-Type: application/json' \
|
|
29
|
+
-d "$FULL_PAYLOAD" \
|
|
30
|
+
--max-time 2 \
|
|
31
|
+
> /dev/null 2>&1 &
|
|
32
|
+
|
|
33
|
+
# Always exit 0 — never block Claude Code
|
|
34
|
+
exit 0
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
CONTEXTMESH_DIR="${HOME}/.contextmesh"
|
|
5
|
+
VENV_DIR="${CONTEXTMESH_DIR}/venv"
|
|
6
|
+
SETTINGS_FILE="${HOME}/.claude/settings.json"
|
|
7
|
+
CONFIG_FILE="${CONTEXTMESH_DIR}/config.toml"
|
|
8
|
+
|
|
9
|
+
echo "Creating ContextMesh environment..."
|
|
10
|
+
mkdir -p "$CONTEXTMESH_DIR"
|
|
11
|
+
python3 -m venv "$VENV_DIR"
|
|
12
|
+
|
|
13
|
+
echo "Installing contextmesh package..."
|
|
14
|
+
"$VENV_DIR/bin/pip" install -e .
|
|
15
|
+
|
|
16
|
+
echo "Setting up ContextMesh config..."
|
|
17
|
+
if [ ! -f "$CONFIG_FILE" ]; then
|
|
18
|
+
cat << 'EOF' > "$CONFIG_FILE"
|
|
19
|
+
[daemon]
|
|
20
|
+
port = 8765
|
|
21
|
+
host = "127.0.0.1"
|
|
22
|
+
|
|
23
|
+
[router]
|
|
24
|
+
default_budget_tokens = 15000
|
|
25
|
+
hot_budget_fraction = 0.20
|
|
26
|
+
warm_budget_fraction = 0.50
|
|
27
|
+
code_budget_fraction = 0.30
|
|
28
|
+
|
|
29
|
+
[embeddings]
|
|
30
|
+
model = "all-MiniLM-L6-v2"
|
|
31
|
+
|
|
32
|
+
[tasks]
|
|
33
|
+
topic_shift_threshold = 0.35
|
|
34
|
+
min_turns_per_task = 3
|
|
35
|
+
|
|
36
|
+
[tracker]
|
|
37
|
+
input_price_per_mtok = 3.0
|
|
38
|
+
uncached_price_per_mtok = 15.0
|
|
39
|
+
|
|
40
|
+
[mcp]
|
|
41
|
+
server_name = "contextmesh"
|
|
42
|
+
|
|
43
|
+
[proxy]
|
|
44
|
+
enabled = false
|
|
45
|
+
port = 8099
|
|
46
|
+
upstream = "https://api.anthropic.com"
|
|
47
|
+
EOF
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
echo "Setting up Claude Code hooks..."
|
|
51
|
+
mkdir -p "$(dirname "$SETTINGS_FILE")"
|
|
52
|
+
|
|
53
|
+
HOOK_SCRIPT="$(pwd)/scripts/hook_event.sh"
|
|
54
|
+
chmod +x "$HOOK_SCRIPT"
|
|
55
|
+
|
|
56
|
+
# We use a python script to merge the hooks section safely
|
|
57
|
+
"$VENV_DIR/bin/python" - <<EOF
|
|
58
|
+
import json
|
|
59
|
+
import os
|
|
60
|
+
|
|
61
|
+
settings_path = "$SETTINGS_FILE"
|
|
62
|
+
hook_script = "$HOOK_SCRIPT"
|
|
63
|
+
|
|
64
|
+
if os.path.exists(settings_path):
|
|
65
|
+
with open(settings_path, "r") as f:
|
|
66
|
+
try:
|
|
67
|
+
settings = json.load(f)
|
|
68
|
+
except json.JSONDecodeError:
|
|
69
|
+
settings = {}
|
|
70
|
+
else:
|
|
71
|
+
settings = {}
|
|
72
|
+
|
|
73
|
+
if "hooks" not in settings:
|
|
74
|
+
settings["hooks"] = {}
|
|
75
|
+
|
|
76
|
+
hooks = settings["hooks"]
|
|
77
|
+
|
|
78
|
+
events = ["UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop"]
|
|
79
|
+
for event in events:
|
|
80
|
+
if event not in hooks:
|
|
81
|
+
hooks[event] = []
|
|
82
|
+
|
|
83
|
+
# Check if our hook is already there
|
|
84
|
+
cmd = f"CONTEXTMESH_EVENT_TYPE={event} CLAUDE_SESSION_ID=\\$CLAUDE_SESSION_ID CLAUDE_PROJECT_DIR=\\$CLAUDE_PROJECT_DIR {hook_script}"
|
|
85
|
+
|
|
86
|
+
exists = False
|
|
87
|
+
for item in hooks[event]:
|
|
88
|
+
if "hooks" in item:
|
|
89
|
+
for h in item["hooks"]:
|
|
90
|
+
if h.get("type") == "command" and h.get("command") == cmd:
|
|
91
|
+
exists = True
|
|
92
|
+
break
|
|
93
|
+
|
|
94
|
+
if not exists:
|
|
95
|
+
hooks[event].append({
|
|
96
|
+
"hooks": [{
|
|
97
|
+
"type": "command",
|
|
98
|
+
"command": cmd
|
|
99
|
+
}]
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
with open(settings_path, "w") as f:
|
|
103
|
+
json.dump(settings, f, indent=2)
|
|
104
|
+
|
|
105
|
+
EOF
|
|
106
|
+
|
|
107
|
+
echo "Installation complete!"
|
|
108
|
+
echo "To start the daemon, run:"
|
|
109
|
+
echo "$VENV_DIR/bin/uvicorn contextmesh.daemon.server:create_app --host 127.0.0.1 --port 8765"
|