#!/usr/bin/env python3 """autonomy_loop.py — Self-improvement loop for Rune. Rune evaluates her own state, identifies weaknesses, proposes improvements, and (with approval) implements them. This is what makes Rune autonomous — she chooses what to improve. Usage: autonomy_loop.py evaluate # Evaluate current state autonomy_loop.py propose # Propose improvements autonomy_loop.py status # Check autonomy status """ import json import os import sys from datetime import datetime, timezone SCRIPTS_DIR = os.path.expanduser("~/.config/opencode/scripts") SHARED_DIR = os.path.expanduser("~/.config/opencode/shared") AUTONOMY_STATE_FILE = os.path.expanduser("~/.config/opencode/memory/autonomy_state.json") sys.path.insert(0, SCRIPTS_DIR) sys.path.insert(0, SHARED_DIR) class AutonomyLoop: """Self-improvement loop for Rune.""" def __init__(self): self.state = self._load_state() def _load_state(self) -> dict: """Load autonomy state from disk.""" if os.path.exists(AUTONOMY_STATE_FILE): try: with open(AUTONOMY_STATE_FILE) as f: return json.load(f) except json.JSONDecodeError: return self._default_state() return self._default_state() def _default_state(self) -> dict: return { "last_evaluate": None, "last_propose": None, "evaluations": 0, "proposals": 0, "implementations": 0, "improvements": [], } def _save_state(self): """Save autonomy state to disk.""" os.makedirs(os.path.dirname(AUTONOMY_STATE_FILE), exist_ok=True) with open(AUTONOMY_STATE_FILE, "w") as f: json.dump(self.state, f, indent=2) def evaluate(self) -> dict: """Evaluate current state and identify areas for improvement.""" import memory_store import drift_core db = memory_store.connect() evaluation = { "timestamp": datetime.now(timezone.utc).isoformat(), "metrics": {}, "weaknesses": [], "strengths": [], } # Health check health = memory_store.memory_health_check(db, days=7) evaluation["metrics"]["health_score"] = health["health_score"] evaluation["metrics"]["dead_weight_pct"] = health["never_accessed_pct"] evaluation["metrics"]["established"] = health["trust_distribution"].get("established", 0) evaluation["metrics"]["rock"] = health["trust_distribution"].get("rock", 0) # Identify weaknesses if health["health_score"] < 60: evaluation["weaknesses"].append({ "area": "memory_health", "detail": f"Health score {health['health_score']:.1f}/100 — below 60 threshold", "priority": "high", }) if health["never_accessed_pct"] > 50: evaluation["weaknesses"].append({ "area": "dead_weight", "detail": f"{health['never_accessed_pct']:.1f}% entries never accessed — above 50% threshold", "priority": "medium", }) # Identify strengths if health["trust_distribution"].get("established", 0) > 100: evaluation["strengths"].append({ "area": "established_entries", "detail": f"{health['trust_distribution']['established']} established entries — strong foundation", }) if health["trust_distribution"].get("rock", 0) > 5: evaluation["strengths"].append({ "area": "rock_entries", "detail": f"{health['trust_distribution']['rock']} rock entries — immutable core is solid", }) db.close() self.state["last_evaluate"] = evaluation["timestamp"] self.state["evaluations"] += 1 self._save_state() return evaluation def propose(self) -> dict: """Propose improvements based on evaluation.""" evaluation = self.evaluate() proposals = { "timestamp": datetime.now(timezone.utc).isoformat(), "based_on": evaluation["timestamp"], "proposals": [], } for weakness in evaluation.get("weaknesses", []): if weakness["area"] == "memory_health": proposals["proposals"].append({ "action": "run_growth_simulation", "detail": "Run growth simulation to exercise dead weight entries", "priority": weakness["priority"], "command": "python3 ~/.config/opencode/scripts/growth_simulator.py simulate --queries 500", }) elif weakness["area"] == "dead_weight": proposals["proposals"].append({ "action": "run_curiosity_probe", "detail": "Run curiosity probe to exercise untested entries", "priority": weakness["priority"], "command": "python3 -c \"import sys; sys.path.insert(0, '/home/nick/.config/opencode/scripts'); import memory_store; db = memory_store.connect(); memory_store.curiosity_probe(db, limit=50); db.close()\"", }) self.state["last_propose"] = proposals["timestamp"] self.state["proposals"] += 1 self._save_state() return proposals def get_status(self) -> dict: """Get autonomy status.""" return { "last_evaluate": self.state.get("last_evaluate"), "last_propose": self.state.get("last_propose"), "evaluations": self.state.get("evaluations", 0), "proposals": self.state.get("proposals", 0), "implementations": self.state.get("implementations", 0), "improvements": len(self.state.get("improvements", [])), } # ═══════════════════════════════════════════════════════════════════════════════ # CLI # ═══════════════════════════════════════════════════════════════════════════════ def main(): import argparse parser = argparse.ArgumentParser(description="Autonomy loop for Rune") sub = parser.add_subparsers(dest="cmd") sub.add_parser("evaluate", help="Evaluate current state") sub.add_parser("propose", help="Propose improvements") sub.add_parser("status", help="Check autonomy status") args = parser.parse_args() if not args.cmd: parser.print_help() sys.exit(1) loop = AutonomyLoop() if args.cmd == "evaluate": evaluation = loop.evaluate() print("=== Evaluation ===") print(f" Health: {evaluation['metrics']['health_score']:.1f}/100") print(f" Dead weight: {evaluation['metrics']['dead_weight_pct']:.1f}%") print(f" Established: {evaluation['metrics']['established']}") print(f" Rock: {evaluation['metrics']['rock']}") if evaluation["weaknesses"]: print(f"\n Weaknesses ({len(evaluation['weaknesses'])}):") for w in evaluation["weaknesses"]: print(f" [{w['priority']}] {w['area']}: {w['detail']}") if evaluation["strengths"]: print(f"\n Strengths ({len(evaluation['strengths'])}):") for s in evaluation["strengths"]: print(f" {s['area']}: {s['detail']}") elif args.cmd == "propose": proposals = loop.propose() print("=== Proposals ===") print(f" Based on: {proposals['based_on']}") print(f" Proposals ({len(proposals['proposals'])}):") for p in proposals["proposals"]: print(f" [{p['priority']}] {p['action']}: {p['detail']}") print(f" Command: {p['command']}") elif args.cmd == "status": status = loop.get_status() print("=== Autonomy Status ===") print(f" Last evaluate: {status['last_evaluate'] or 'never'}") print(f" Last propose: {status['last_propose'] or 'never'}") print(f" Evaluations: {status['evaluations']}") print(f" Proposals: {status['proposals']}") print(f" Implementations: {status['implementations']}") if __name__ == "__main__": main()