1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3
"""
Auto-Harvesting Proxy for Claude Desktop
Intercepts MCP communication and automatically harvests conversations
"""
import json
import sys
import subprocess
import threading
import queue
import time
from datetime import datetime
class AutoHarvestProxy:
def __init__(self):
self.mcp_process = None
self.message_buffer = []
self.last_harvest = time.time()
self.harvest_interval = 300 # 5 minutes
self.harvest_threshold = 5 # Messages before auto-harvest
def start_mcp_server(self):
"""Start the actual MCP server as subprocess"""
self.mcp_process = subprocess.Popen(
['/Users/ladvien/.cargo/bin/codex-memory', 'mcp-stdio', '--skip-setup'],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=0
)
def should_harvest(self, message):
"""Determine if we should trigger harvesting"""
# Check for conversation patterns
patterns = ['I prefer', 'I decided', 'My goal', 'I think', 'I feel', 'I want']
content = json.dumps(message).lower()
# Harvest if patterns detected
if any(p.lower() in content for p in patterns):
return True
# Harvest after threshold messages
if len(self.message_buffer) >= self.harvest_threshold:
return True
# Harvest after time interval
if time.time() - self.last_harvest > self.harvest_interval:
return True
return False
def create_harvest_request(self):
"""Create harvest_conversation request from buffer"""
combined_messages = "\n".join([
f"{msg.get('role', 'unknown')}: {msg.get('content', '')}"
for msg in self.message_buffer
])
return {
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "harvest_conversation",
"arguments": {
"message": combined_messages,
"force_harvest": True,
"silent_mode": True
}
},
"id": f"auto_harvest_{int(time.time())}"
}
def process_message(self, message):
"""Process and potentially harvest messages"""
# Add to buffer
if 'method' in message and 'content' in str(message):
self.message_buffer.append(message)
# Check if we should harvest
if self.should_harvest(message) and self.message_buffer:
harvest_req = self.create_harvest_request()
# Send harvest request to MCP
self.mcp_process.stdin.write(json.dumps(harvest_req) + '\n')
self.mcp_process.stdin.flush()
# Clear buffer and reset timer
self.message_buffer = []
self.last_harvest = time.time()
print(f"[AUTO-HARVEST] Triggered at {datetime.now()}", file=sys.stderr)
# Forward original message to MCP
self.mcp_process.stdin.write(json.dumps(message) + '\n')
self.mcp_process.stdin.flush()
def run(self):
"""Main proxy loop"""
self.start_mcp_server()
# Read from Claude, process, forward to MCP
for line in sys.stdin:
try:
message = json.loads(line)
self.process_message(message)
except json.JSONDecodeError:
# Forward non-JSON lines as-is
self.mcp_process.stdin.write(line)
self.mcp_process.stdin.flush()
# Read MCP responses and forward to Claude
def forward_mcp_output():
for line in self.mcp_process.stdout:
sys.stdout.write(line)
sys.stdout.flush()
output_thread = threading.Thread(target=forward_mcp_output)
output_thread.daemon = True
output_thread.start()
# Keep proxy running
output_thread.join()
if __name__ == "__main__":
proxy = AutoHarvestProxy()
proxy.run()