Heartbeat: auto-detect and commit skill changes
Now watches /data/skills/ for changes on every heartbeat tick. Commits and re-packages automatically. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dd91089be0
commit
7afc878b3b
@ -1,2 +1,7 @@
|
||||
{"timestamp": "2026-03-19T19:41:19.517373", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T19:41:38.652515", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T19:46:23.559272", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T19:51:43.565628", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T19:56:48.576386", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T20:02:01.418535", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "health": "healthy"}
|
||||
{"timestamp": "2026-03-19T20:03:15.583444", "claude_cli": {"status": "ok", "detail": "authenticated"}, "disk": {"status": "ok", "total": "915G", "used": "20G", "available": "849G", "use_pct": "3%"}, "api_server": {"status": "ok", "detail": "active"}, "ledger": {"calls_today": 4, "cost_today": 0.062}, "queue": {"processed": 0}, "skills": {"status": "clean", "changes": 0}, "health": "healthy"}
|
||||
|
||||
@ -6,6 +6,7 @@ Run by systemd timer every 5 minutes. This is Symbiont's autonomic nervous syste
|
||||
- Process any pending tasks in the queue
|
||||
- Check rate limit status and clear expired limits
|
||||
- Log a heartbeat to the ledger for uptime tracking
|
||||
- Auto-detect skill changes, commit them, and re-package
|
||||
- Basic self-diagnostics
|
||||
"""
|
||||
|
||||
@ -129,6 +130,44 @@ def process_queue():
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def check_skills():
|
||||
"""Detect skill changes, commit to git, and re-package."""
|
||||
try:
|
||||
skills_dir = Path("/data/skills")
|
||||
if not skills_dir.exists():
|
||||
return {"status": "skipped", "reason": "skills dir not found"}
|
||||
|
||||
# Check if there are any uncommitted changes in /data/skills
|
||||
result = subprocess.run(
|
||||
["git", "status", "--porcelain"],
|
||||
cwd=skills_dir, capture_output=True, text=True, timeout=10
|
||||
)
|
||||
changed_files = result.stdout.strip()
|
||||
|
||||
if not changed_files:
|
||||
return {"status": "clean", "changes": 0}
|
||||
|
||||
# Count changed skills
|
||||
change_count = len(changed_files.splitlines())
|
||||
|
||||
# Commit changes
|
||||
subprocess.run(["git", "add", "-A"], cwd=skills_dir, capture_output=True, timeout=10)
|
||||
subprocess.run(
|
||||
["git", "commit", "-m",
|
||||
f"Auto-commit: {change_count} skill file(s) updated by heartbeat\n\nCo-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"],
|
||||
cwd=skills_dir, capture_output=True, timeout=10
|
||||
)
|
||||
|
||||
# Re-package all skills
|
||||
package_script = skills_dir / "package_all.sh"
|
||||
if package_script.exists():
|
||||
subprocess.run(["bash", str(package_script)], cwd=skills_dir, capture_output=True, timeout=60)
|
||||
|
||||
return {"status": "committed", "changes": change_count}
|
||||
except Exception as e:
|
||||
return {"status": "error", "detail": str(e)}
|
||||
|
||||
|
||||
def run_heartbeat():
|
||||
"""Run all checks and log the heartbeat."""
|
||||
logger.info("Heartbeat starting")
|
||||
@ -140,6 +179,7 @@ def run_heartbeat():
|
||||
"api_server": check_api_server(),
|
||||
"ledger": get_ledger_stats(),
|
||||
"queue": process_queue(),
|
||||
"skills": check_skills(),
|
||||
}
|
||||
|
||||
# Determine overall health
|
||||
@ -159,6 +199,7 @@ def run_heartbeat():
|
||||
logger.info(f"Health: {heartbeat['health']} | "
|
||||
f"CLI: {heartbeat['claude_cli']['status']} | "
|
||||
f"API: {heartbeat['api_server']['status']} | "
|
||||
f"Skills: {heartbeat['skills']['status']} | "
|
||||
f"Queue processed: {heartbeat['queue'].get('processed', 0)} | "
|
||||
f"Today's calls: {heartbeat['ledger']['calls_today']} "
|
||||
f"(${heartbeat['ledger']['cost_today']})")
|
||||
|
||||
Loading…
Reference in New Issue
Block a user