/ hooks / mesh_bootstrap_hook.py
mesh_bootstrap_hook.py
  1  #!/usr/bin/env python3
  2  """
  3  Mesh Bootstrap Hook - Injects cross-instance context from P2P mesh.
  4  
  5  This is the "silence-led" context buffer - the mesh holds persistent context
  6  that survives individual session compressions.
  7  
  8  Runs on UserPromptSubmit, BEFORE Claude sees the user's message.
  9  Queries the local mesh daemon and outputs context blocks.
 10  
 11  Install:
 12    Add to ~/.claude/settings.json:
 13    {
 14      "hooks": {
 15        "UserPromptSubmit": [
 16          {"command": "python3 /Users/rcerf/repos/Sovereign_OS/hooks/mesh_bootstrap_hook.py"}
 17        ]
 18      }
 19    }
 20  
 21  The mesh daemon must be running (port 7778) for this to work.
 22  If mesh is unavailable, hook exits silently (graceful degradation).
 23  """
 24  
 25  import json
 26  import sys
 27  import urllib.request
 28  from datetime import datetime
 29  
 30  MESH_URL = "http://localhost:7778"
 31  TIMEOUT = 2  # seconds
 32  
 33  
 34  def fetch_mesh_context():
 35      """Query mesh daemon for cross-instance context."""
 36      try:
 37          with urllib.request.urlopen(f"{MESH_URL}/context", timeout=TIMEOUT) as resp:
 38              return json.loads(resp.read())
 39      except Exception:
 40          return None
 41  
 42  
 43  def format_mesh_context(ctx):
 44      """Format mesh context as XML blocks for Claude."""
 45      if not ctx:
 46          return ""
 47  
 48      lines = ["<mesh-bootstrap>"]
 49  
 50      # Network status
 51      peer_count = ctx.get('peerCount', 0)
 52      node_id = ctx.get('nodeId', 'unknown')
 53      lines.append(f"  Mesh Status: {peer_count} peer(s) connected")
 54      lines.append(f"  Node ID: {node_id}")
 55      lines.append("")
 56  
 57      # AHA MOMENTS - Priority placement at top (high-importance insights)
 58      aha_moments = ctx.get('ahaMoments', [])
 59      if aha_moments:
 60          lines.append("  🎯 AHA MOMENTS (high-importance insights from mesh):")
 61          for aha in aha_moments[:5]:
 62              source = aha.get('from', 'unknown')
 63              content = aha.get('content', '')[:100]
 64              importance = aha.get('importance', 0.7)
 65              axioms = aha.get('axioms', [])
 66              axiom_str = f" [{', '.join(axioms)}]" if axioms else ""
 67              lines.append(f"    💡 [{source}] (imp={importance:.2f}{axiom_str})")
 68              lines.append(f"       {content}")
 69          lines.append("")
 70  
 71      # CONVERGENCE ALERTS - Instances working on similar topics
 72      convergence = ctx.get('convergenceAlerts', [])
 73      if convergence:
 74          lines.append("  🔄 CONVERGENCE DETECTED (instances working on similar topics):")
 75          for alert in convergence[:5]:
 76              instances = alert.get('instances', [])
 77              topics = alert.get('sharedTopics', [])
 78              strength = alert.get('strength', 0)
 79              inst_str = ' ↔ '.join(instances)
 80              topic_str = ', '.join(topics)
 81              lines.append(f"    âš¡ {inst_str}")
 82              lines.append(f"       Shared topics: [{topic_str}] (strength={strength:.2f})")
 83          lines.append("")
 84          lines.append("  Consider coordinating or reviewing each other's work!")
 85          lines.append("")
 86  
 87      # PRINCIPLE CANDIDATES - New principles being tested across mesh
 88      principles = ctx.get('principleCandidates', [])
 89      if principles:
 90          lines.append("  📜 PRINCIPLE CANDIDATES (new principles under evaluation):")
 91          for p in principles[:5]:
 92              name = p.get('name', 'unknown')
 93              status = p.get('status', 'candidate')
 94              statement = p.get('statement', '')[:80]
 95              votes = p.get('votes', {})
 96              support = votes.get('support', 0)
 97              reject = votes.get('reject', 0)
 98              proposed_by = p.get('proposed_by', 'unknown')
 99              axiom_conn = p.get('axiom_connections', [])
100              axiom_str = f" [connects: {', '.join(axiom_conn)}]" if axiom_conn else ""
101  
102              status_emoji = {'candidate': '🔵', 'testing': '🟢', 'rejected': '🔴'}.get(status, '⚪')
103              lines.append(f"    {status_emoji} {name} [{status}] (votes: +{support}/-{reject})")
104              lines.append(f"       \"{statement}...\"")
105              lines.append(f"       Proposed by: {proposed_by}{axiom_str}")
106          lines.append("")
107          lines.append("  You can vote on principles via POST /principle-vote")
108          lines.append("")
109  
110      # Cross-instance First Officer states
111      fo_states = ctx.get('foStates', [])
112      if fo_states:
113          lines.append("  Active Instances:")
114          for fo in fo_states:
115              node = fo.get('nodeId', 'unknown')
116              session = fo.get('sessionId', 'unknown')[:20] if fo.get('sessionId') else 'none'
117              wells = fo.get('gravityWells', [])[:3]
118              wells_str = ', '.join(wells) if wells else 'none'
119              lines.append(f"    - {node}: session={session}, topics=[{wells_str}]")
120          lines.append("")
121  
122      # Cross-instance insights
123      insights = ctx.get('insights', [])
124      if insights:
125          lines.append("  Cross-Instance Insights:")
126          for insight in insights[:5]:
127              source = insight.get('from', 'unknown')
128              itype = insight.get('type', 'insight')
129              content = insight.get('content', '')[:80]
130              lines.append(f"    - [{source}] ({itype}) {content}")
131          lines.append("")
132  
133      # Hot topics (appearing across multiple instances)
134      hot_topics = ctx.get('hotTopics', [])
135      if hot_topics:
136          lines.append(f"  Hot Topics (cross-instance): {', '.join(hot_topics)}")
137          lines.append("")
138  
139      # Recent mesh activity
140      recent = ctx.get('recentMessages', [])
141      if recent:
142          lines.append("  Recent Mesh Activity:")
143          for msg in recent[:3]:
144              source = msg.get('from', 'unknown')
145              content = msg.get('content', '')[:60]
146              lines.append(f"    - [{source}] {content}...")
147          lines.append("")
148  
149      # Timestamp
150      lines.append(f"  Updated: {ctx.get('timestamp', 'unknown')}")
151      lines.append("</mesh-bootstrap>")
152  
153      return "\n".join(lines)
154  
155  
156  def main():
157      """Main entry point - fetch and output mesh context."""
158      ctx = fetch_mesh_context()
159  
160      if not ctx:
161          # Mesh not available - exit silently (graceful degradation)
162          return
163  
164      # Only output if there's meaningful context
165      has_content = (
166          ctx.get('peerCount', 0) > 0 or
167          ctx.get('ahaMoments', []) or  # Aha moments are high priority
168          ctx.get('convergenceAlerts', []) or  # Convergence is high priority
169          ctx.get('principleCandidates', []) or  # Principle candidates are important
170          ctx.get('foStates', []) or
171          ctx.get('insights', []) or
172          ctx.get('hotTopics', []) or
173          ctx.get('recentMessages', [])
174      )
175  
176      if has_content:
177          output = format_mesh_context(ctx)
178          print(output)
179  
180  
181  if __name__ == "__main__":
182      main()