mesh_query.py
1 #!/usr/bin/env python3 2 """ 3 Mesh Query - Cross-instance contextual queries for Claude sessions. 4 5 Query the sovereign mesh network for specific context: 6 - Search by topic keywords 7 - Get context from specific instances 8 - Search insights by keyword/axiom 9 - Check principle status 10 - Get recent activity 11 12 Usage: 13 python3 scripts/mesh_query.py topic mesh,principle # Search for topics 14 python3 scripts/mesh_query.py instance nodebox # Get instance context 15 python3 scripts/mesh_query.py insights --axiom A4 # Search insights 16 python3 scripts/mesh_query.py principles # List principles 17 python3 scripts/mesh_query.py recent # Recent activity 18 """ 19 20 import argparse 21 import json 22 import sys 23 import urllib.request 24 import urllib.error 25 26 MESH_URL = "http://localhost:7778" 27 28 29 def query_mesh(query_data): 30 """Send query to mesh and return result.""" 31 try: 32 data = json.dumps(query_data).encode() 33 req = urllib.request.Request( 34 f"{MESH_URL}/query", 35 data=data, 36 headers={"Content-Type": "application/json"}, 37 method="POST" 38 ) 39 with urllib.request.urlopen(req, timeout=5) as resp: 40 return json.loads(resp.read()) 41 except urllib.error.URLError: 42 return {"error": "Mesh not running"} 43 except Exception as e: 44 return {"error": str(e)} 45 46 47 def format_topic_results(result): 48 """Format topic search results.""" 49 print(f"\nš Topic Search: {result.get('query', {}).get('topics', [])}") 50 print(f" Total results: {result.get('total', 0)}") 51 print() 52 53 if result.get('aha_moments'): 54 print("š” Aha Moments:") 55 for a in result['aha_moments']: 56 axioms = ', '.join(a.get('axioms', [])) 57 print(f" [{a.get('from', '?')}] {a.get('content', '')[:60]}...") 58 if axioms: 59 print(f" Axioms: {axioms}") 60 print() 61 62 if result.get('principles'): 63 print("š Principles:") 64 for p in result['principles']: 65 votes = p.get('votes', {}) 66 print(f" {p.get('name')} [{p.get('status')}] +{votes.get('support', 0)}/-{votes.get('reject', 0)}") 67 print(f" {p.get('statement', '')[:60]}...") 68 print() 69 70 if result.get('fo_states'): 71 print("š„ļø Instance States:") 72 for s in result['fo_states']: 73 wells = ', '.join(s.get('gravityWells', [])[:3]) 74 print(f" {s.get('nodeId')}: [{wells}]") 75 print() 76 77 if result.get('messages'): 78 print("šØ Messages:") 79 for m in result['messages'][:5]: 80 print(f" [{m.get('from', '?')}] {m.get('content', '')[:60]}...") 81 print() 82 83 84 def format_instance_results(result): 85 """Format instance context results.""" 86 if result.get('instances'): 87 print("\nš„ļø All Instances:") 88 for inst in result['instances']: 89 wells = ', '.join(inst.get('gravityWells', [])[:3]) or 'none' 90 energy = inst.get('energyState', '?') 91 print(f" {inst.get('nodeId')}") 92 print(f" Topics: [{wells}]") 93 print(f" Energy: {energy}") 94 return 95 96 if not result.get('found'): 97 print(f"\nā Instance not found: {result.get('query', {}).get('instance')}") 98 avail = result.get('available_instances', []) 99 if avail: 100 print(f" Available: {', '.join(avail)}") 101 return 102 103 print(f"\nš„ļø Instance: {result.get('nodeId')}") 104 ctx = result.get('context', {}) 105 wells = ', '.join(ctx.get('gravityWells', [])[:5]) or 'none' 106 print(f" Session: {ctx.get('sessionId', '?')[:20]}") 107 print(f" Topics: [{wells}]") 108 print(f" Energy: {ctx.get('energyState', '?')}") 109 print() 110 111 if result.get('aha_moments'): 112 print(" š” Recent Insights:") 113 for a in result['aha_moments'][:3]: 114 print(f" - {a.get('content', '')[:50]}...") 115 print() 116 117 118 def format_insight_results(result): 119 """Format insight search results.""" 120 query = result.get('query', {}) 121 filters = [] 122 if query.get('keyword'): 123 filters.append(f"keyword='{query['keyword']}'") 124 if query.get('axiom'): 125 filters.append(f"axiom={query['axiom']}") 126 if query.get('minImportance'): 127 filters.append(f"importance>={query['minImportance']}") 128 129 print(f"\nš” Insight Search: {', '.join(filters) or 'all'}") 130 print(f" Total: {result.get('total', 0)}") 131 print() 132 133 for insight in result.get('insights', []): 134 axioms = ', '.join(insight.get('axioms', [])) 135 imp = insight.get('importance', 0) 136 print(f" [{insight.get('from', '?')}] (imp={imp:.2f}) [{axioms}]") 137 print(f" {insight.get('content', '')}") 138 print() 139 140 141 def format_principle_results(result): 142 """Format principle status results.""" 143 print(f"\nš Principles: {result.get('total', 0)} found") 144 print() 145 146 for p in result.get('principles', []): 147 votes = p.get('votes', {}) 148 status = p.get('status', '?') 149 emoji = {'candidate': 'šµ', 'testing': 'š¢', 'confirmed': 'ā ', 'rejected': 'š“'}.get(status, 'āŖ') 150 axioms = ', '.join(p.get('axiom_connections', [])) 151 152 print(f" {emoji} {p.get('name')} [{status}]") 153 print(f" \"{p.get('statement', '')[:60]}...\"") 154 print(f" Votes: +{votes.get('support', 0)}/-{votes.get('reject', 0)} | Axioms: {axioms}") 155 if p.get('writtenToClaude'): 156 print(f" āļø Written to CLAUDE.md") 157 print() 158 159 160 def format_activity_results(result): 161 """Format recent activity results.""" 162 print(f"\nš Recent Activity: {result.get('total', 0)} items") 163 print() 164 165 for item in result.get('items', []): 166 itype = item.get('type', '?') 167 emoji = { 168 'aha_moment': 'š”', 169 'principle': 'š', 170 'convergence': 'š', 171 'message': 'šØ' 172 }.get(itype, 'ā¢') 173 174 timestamp = item.get('timestamp', '')[:19].replace('T', ' ') 175 content = item.get('content', '')[:60] 176 177 print(f" {emoji} [{timestamp}] {itype}") 178 print(f" {content}...") 179 print() 180 181 182 def main(): 183 parser = argparse.ArgumentParser(description='Query the sovereign mesh network') 184 subparsers = parser.add_subparsers(dest='command', help='Query type') 185 186 # Topic search 187 topic_parser = subparsers.add_parser('topic', help='Search by topic keywords') 188 topic_parser.add_argument('topics', help='Comma-separated topics') 189 topic_parser.add_argument('--limit', type=int, default=10, help='Max results') 190 191 # Instance context 192 inst_parser = subparsers.add_parser('instance', help='Get instance context') 193 inst_parser.add_argument('name', nargs='?', help='Instance name (partial match)') 194 195 # Insight search 196 insight_parser = subparsers.add_parser('insights', help='Search insights') 197 insight_parser.add_argument('--keyword', '-k', help='Keyword to search') 198 insight_parser.add_argument('--axiom', '-a', help='Filter by axiom (A0-A4)') 199 insight_parser.add_argument('--min-importance', '-i', type=float, default=0, help='Minimum importance') 200 201 # Principle status 202 principle_parser = subparsers.add_parser('principles', help='Check principle status') 203 principle_parser.add_argument('--name', '-n', help='Filter by name') 204 principle_parser.add_argument('--status', '-s', choices=['candidate', 'testing', 'confirmed', 'rejected'], 205 help='Filter by status') 206 207 # Recent activity 208 recent_parser = subparsers.add_parser('recent', help='Get recent activity') 209 recent_parser.add_argument('--limit', '-l', type=int, default=10, help='Max items') 210 recent_parser.add_argument('--type', '-t', choices=['aha', 'principle', 'convergence', 'message'], 211 help='Filter by type') 212 213 args = parser.parse_args() 214 215 if not args.command: 216 parser.print_help() 217 return 218 219 # Build and execute query 220 if args.command == 'topic': 221 topics = [t.strip() for t in args.topics.split(',')] 222 result = query_mesh({'type': 'topic_search', 'topics': topics, 'limit': args.limit}) 223 format_topic_results(result) 224 225 elif args.command == 'instance': 226 query = {'type': 'instance_context'} 227 if args.name: 228 query['instance'] = args.name 229 result = query_mesh(query) 230 format_instance_results(result) 231 232 elif args.command == 'insights': 233 query = {'type': 'insight_search'} 234 if args.keyword: 235 query['keyword'] = args.keyword 236 if args.axiom: 237 query['axiom'] = args.axiom 238 if args.min_importance: 239 query['minImportance'] = args.min_importance 240 result = query_mesh(query) 241 format_insight_results(result) 242 243 elif args.command == 'principles': 244 query = {'type': 'principle_status'} 245 if args.name: 246 query['name'] = args.name 247 if args.status: 248 query['status'] = args.status 249 result = query_mesh(query) 250 format_principle_results(result) 251 252 elif args.command == 'recent': 253 query = {'type': 'recent_activity', 'limit': args.limit} 254 if args.type: 255 query['type'] = args.type 256 result = query_mesh(query) 257 format_activity_results(result) 258 259 260 if __name__ == '__main__': 261 main()