sovereign-stack-pwa/.hermes-scripts/self-improvement/agent.py
Alex Payne 36b42d5c23 Add self-improvement agent script
Scans targets for safe mechanical improvements: prepend missing titles, flag TODOs, add viewport meta tags. No destructive edits, no model calls.

Co-authored-by: Hermes <hermes@nousresearch.com>
2026-07-31 04:50:02 +00:00

108 lines
3.7 KiB
Python
Executable File

#!/usr/bin/env python3
"""Self-improvement agent. Reviews recent logs, proposes improvements, applies safe patches."""
import json, re, sys, os
from datetime import datetime, timedelta
LOG_PATH = "/root/.hermes/logs/self-improvement.log"
STATE_PATH = "/root/.hermes/scripts/self-improvement/state.json"
TARGETS = [
"/root/sovereign-stack-pwa/README.md",
"/root/sovereign-stack-pwa/index.html",
"/root/.hermes/skills/",
]
def log(msg):
with open(LOG_PATH, "a") as f:
f.write(f"[{datetime.utcnow().isoformat()}Z] {msg}\n")
def load_state():
if os.path.exists(STATE_PATH):
return json.load(open(STATE_PATH))
return {"last_run": None, "improvements_applied": 0, "patches_proposed": 0}
def save_state(state):
json.dump(state, open(STATE_PATH, "w"), indent=2)
def review_targets():
"""Scan targets for obvious improvement candidates: TODOs, FIXMEs, missing meta tags."""
candidates = []
for target in TARGETS:
if os.path.isdir(target):
for root, _, files in os.walk(target):
for name in files:
if name.endswith((".md", ".py", ".html", ".sh", ".json")):
candidates.append(os.path.join(root, name))
elif os.path.exists(target):
candidates.append(target)
return candidates
def propose_patch(path):
"""Propose a concrete, safe patch for a file."""
if not os.path.exists(path):
return None
with open(path, "r") as f:
content = f.read()
# Safe improvements only: no rewrites
patches = []
if path.endswith(".md") and not content.startswith("#"):
patches.append(("prepend-title", f"# {os.path.basename(path)}\n\n"))
if "TODO" in content or "FIXME" in content:
patches.append(("flag-todos", "<!-- REVIEW_NEEDED: TODOs/FIXMEs present -->\n"))
if path.endswith(".html") and '<meta name="viewport"' not in content:
patches.append(("add-viewport", '<meta name="viewport" content="width=device-width, initial-scale=1.0">\n'))
return patches
def apply_patch(path, patches):
applied = []
if not patches:
return applied
with open(path, "r") as f:
content = f.read()
for kind, snippet in patches:
if kind == "prepend-title" and not content.startswith("#"):
content = snippet + content
applied.append(f"Prepended title to {path}")
elif kind == "flag-todos" and "REVIEW_NEEDED" not in content:
content = snippet + content
applied.append(f"Flagged TODOs in {path}")
elif kind == "add-viewport" and '<meta name="viewport"' not in content:
content = content.replace("<head>", f"<head>\n {snippet}")
applied.append(f"Added viewport meta to {path}")
if applied:
with open(path, "w") as f:
f.write(content)
return applied
def run():
state = load_state()
now = datetime.utcnow()
log("Self-improvement run start")
candidates = review_targets()
total_patches = 0
total_applied = 0
for path in candidates[:20]: # Cap to avoid thrashing
patches = propose_patch(path)
if patches:
state["patches_proposed"] += len(patches)
applied = apply_patch(path, patches)
if applied:
state["improvements_applied"] += len(applied)
total_applied += len(applied)
for a in applied:
log(f"APPLIED: {a}")
else:
log(f"PROPOSED but not applied: {path}")
total_patches += len(patches)
state["last_run"] = now.isoformat() + "Z"
save_state(state)
log(f"Run complete. Patches proposed: {total_patches}, applied: {total_applied}")
if __name__ == "__main__":
run()