codex-memory 0.1.40

An advanced hierarchical memory system for AI agents with MCP integration
Documentation
#!/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()