#!/usr/bin/env python3 """ Hermes Profile Inspector - Inspects a Hermes profile and outputs structured JSON. Usage: python3 profile-inspector.py Outputs JSON with: model, provider, skill_count, cron_count, verification status. """ import json import os import sys from pathlib import Path from typing import Any def discover_model_provider(profile_name: str) -> tuple[str, str]: """Discover model and provider from profile config.yaml""" config_path = Path(f"/root/.hermes/profiles/{profile_name}/config.yaml") if not config_path.exists(): return "unknown", "unknown" try: import yaml with open(config_path) as f: cfg = yaml.safe_load(f) model_config = cfg.get("model", {}) if isinstance(model_config, dict): model = model_config.get("default", "unknown") provider = model_config.get("provider", "unknown") else: model = str(model_config) provider = "unknown" return str(model), str(provider) except Exception: return "unknown", "unknown" def discover_skills(profile_path: Path) -> list[str]: """Discover skill names from profile skills directory""" skills_dir = profile_path / "skills" if not skills_dir.exists(): return [] skills = [] for skill_dir in skills_dir.rglob("*"): if skill_dir.is_dir(): skill_info = skill_dir / "SKILL.md" if skill_info.exists(): skills.append(skill_dir.name) return sorted(set(skills)) def discover_crons(profile_path: Path) -> list[str]: """Discover cron job names from profile cron directory""" cron_dir = profile_path / "cron" if not cron_dir.exists(): return [] crons = [] for item in cron_dir.iterdir(): if item.is_file() and item.suffix == ".py": crons.append(item.stem) return sorted(crons) def _find_in_dict(data, target, depth=0, max_depth=10): """Recursively search for target key in nested dict/list structure""" if depth > max_depth: return False if isinstance(data, dict): if target in data: return True for v in data.values(): if _find_in_dict(v, target, depth + 1, max_depth): return True elif isinstance(data, list): for item in data: if _find_in_dict(item, target, depth + 1, max_depth): return True return False def verify_model_chain(profile_name: str, model: str, provider: str) -> dict[str, Any]: """Verify the model exists in provider's model cache""" models_cache_path = Path(f"/root/.hermes/profiles/{profile_name}/models_dev_cache.json") if not models_cache_path.exists(): return {"cache_found": False} try: with open(models_cache_path) as f: cache = json.load(f) # Check if model is in cache (recursively search nested structure) model_found = _find_in_dict(cache, model) return { "cache_found": True, "model_in_cache": model_found, "model": model, "provider": provider } except Exception as e: return {"cache_found": True, "error": str(e)} def build_profile_report(profile_name: str) -> dict[str, Any]: """Build structured report for a Hermes profile""" profile_path = Path(f"/root/.hermes/profiles/{profile_name}") if not profile_path.exists(): return {"error": f"Profile {profile_name} not found", "exists": False} model, provider = discover_model_provider(profile_name) skills = discover_skills(profile_path) crons = discover_crons(profile_path) # Count files in profile stat = profile_path.stat() return { "exists": True, "profile": profile_name, "model": model, "provider": provider, "skills": { "count": len(skills), "names": skills }, "crons": { "count": len(crons), "names": crons }, "profile_path": str(profile_path), "memory_kb": stat.st_size // 1024, "verified": True } if __name__ == "__main__": if len(sys.argv) < 2: print(json.dumps({"error": "Usage: profile-inspector.py "})) sys.exit(1) profile = sys.argv[1] report = build_profile_report(profile) if report.get("exists"): model = report.get("model", "unknown") provider = report.get("provider", "unknown") report["model_verification"] = verify_model_chain(profile, model, provider) print(json.dumps(report, indent=2))