#!/usr/bin/env python3 """Parse agents.yaml and output agent info in shell-friendly format. Usage: python3 parse_agents.py list # list agent IDs python3 parse_agents.py info # get agent info as KEY=VALUE python3 parse_agents.py services # list all agents with service details python3 parse_agents.py ids # space-separated agent IDs (for bash loops) """ import sys import yaml from pathlib import Path AGENTS_YAML = Path(__file__).resolve().parent.parent / 'agents.yaml' def load(): with open(AGENTS_YAML, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {} def cmd_list(data): for aid, agent in data.get('agents', {}).items(): print(f"{aid}\t{agent.get('type', 'unknown')}\t{agent.get('name', '')}") def cmd_ids(data): print(' '.join(data.get('agents', {}).keys())) def _shell_quote(val): """Escape a value for safe bash eval: wrap in single quotes, escape inner quotes.""" s = str(val) return "'" + s.replace("'", "'\\''") + "'" def cmd_info(data, agent_id): agents = data.get('agents', {}) if agent_id not in agents: print(f"AGENT_FOUND=false", file=sys.stderr) sys.exit(1) a = agents[agent_id] svc = a.get('service', {}) defaults = data.get('defaults', {}) print(f"AGENT_ID={_shell_quote(agent_id)}") print(f"AGENT_NAME={_shell_quote(a.get('name', ''))}") print(f"AGENT_TYPE={_shell_quote(a.get('type', 'local-systemd'))}") print(f"PROFILE_DIR={_shell_quote(a.get('profile_dir', ''))}") print(f"WORKSPACE={_shell_quote(a.get('workspace', ''))}") print(f"ENV_FILE={_shell_quote(a.get('env_file', ''))}") print(f"IS_HUB={_shell_quote(str(a.get('is_hub', False)).lower())}") print(f"QDRANT_HOST={_shell_quote(a.get('qdrant_host', defaults.get('qdrant_host', 'localhost')))}") if a.get('type') == 'local-cli': print(f"CHECK_CMD={_shell_quote(svc.get('check_cmd', ''))}") print(f"START_CMD={_shell_quote(svc.get('start_cmd', ''))}") print(f"CHECK_PATTERN={_shell_quote(svc.get('check_pattern', ''))}") elif a.get('type') == 'local-systemd': unit = svc.get('unit', f"openclaw-gateway-{agent_id}.service") print(f"SYSTEMD_UNIT={_shell_quote(unit)}") elif a.get('type') == 'remote-http': print(f"HEALTH_URL={_shell_quote(svc.get('health_url', ''))}") print(f"TIMEOUT={_shell_quote(svc.get('timeout', 5000))}") def cmd_services(data): """Output all agents in tab-separated format suitable for bash/JS parsing.""" agents = data.get('agents', {}) for aid, a in agents.items(): svc = a.get('service', {}) t = a.get('type', 'local-systemd') if t == 'local-cli': print(f"{aid}\t{t}\t{svc.get('check_cmd', '')}\t{svc.get('start_cmd', '')}\t{svc.get('check_pattern', '')}") elif t == 'local-systemd': unit = svc.get('unit', f"openclaw-gateway-{aid}.service") print(f"{aid}\t{t}\t{unit}") elif t == 'remote-http': print(f"{aid}\t{t}\t{svc.get('health_url', '')}\t{svc.get('timeout', 5000)}") if __name__ == '__main__': if len(sys.argv) < 2: print(__doc__) sys.exit(1) data = load() cmd = sys.argv[1] if cmd == 'list': cmd_list(data) elif cmd == 'ids': cmd_ids(data) elif cmd == 'info' and len(sys.argv) > 2: cmd_info(data, sys.argv[2]) elif cmd == 'services': cmd_services(data) else: print(__doc__) sys.exit(1)