diff --git a/automation/agent-info.py b/automation/agent-info.py new file mode 100755 index 0000000..deb6c2e --- /dev/null +++ b/automation/agent-info.py @@ -0,0 +1,284 @@ +#!/usr/bin/env python3 +""" +Show information about available agents. +Usage: python3 agent-info.py [--tree] [name] +""" + +import argparse +import json +import re +import sys +from pathlib import Path +from typing import Dict, List, Optional + +CLAUDE_DIR = Path.home() / ".claude" +AGENTS_DIR = CLAUDE_DIR / "agents" +REGISTRY_PATH = CLAUDE_DIR / "state" / "component-registry.json" + + +# Agent hierarchy (from CLAUDE.md) +HIERARCHY = { + "personal-assistant": { + "supervisor": None, + "subordinates": ["master-orchestrator"] + }, + "master-orchestrator": { + "supervisor": "personal-assistant", + "subordinates": ["linux-sysadmin", "k8s-orchestrator", "programmer-orchestrator"] + }, + "linux-sysadmin": { + "supervisor": "master-orchestrator", + "subordinates": [] + }, + "k8s-orchestrator": { + "supervisor": "master-orchestrator", + "subordinates": ["k8s-diagnostician", "argocd-operator", "prometheus-analyst", "git-operator"] + }, + "k8s-diagnostician": { + "supervisor": "k8s-orchestrator", + "subordinates": [] + }, + "argocd-operator": { + "supervisor": "k8s-orchestrator", + "subordinates": [] + }, + "prometheus-analyst": { + "supervisor": "k8s-orchestrator", + "subordinates": [] + }, + "git-operator": { + "supervisor": "k8s-orchestrator", + "subordinates": [] + }, + "programmer-orchestrator": { + "supervisor": "master-orchestrator", + "subordinates": ["code-planner", "code-implementer", "code-reviewer"] + }, + "code-planner": { + "supervisor": "programmer-orchestrator", + "subordinates": [] + }, + "code-implementer": { + "supervisor": "programmer-orchestrator", + "subordinates": [] + }, + "code-reviewer": { + "supervisor": "programmer-orchestrator", + "subordinates": [] + } +} + + +def load_registry() -> Dict: + """Load component registry.""" + try: + with open(REGISTRY_PATH) as f: + return json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + return {} + + +def find_agent_files() -> List[Path]: + """Find all agent markdown files.""" + if not AGENTS_DIR.exists(): + return [] + + return [f for f in AGENTS_DIR.glob("*.md") + if f.name != "README.md"] + + +def parse_agent_md(path: Path) -> Dict: + """Parse an agent markdown file for metadata.""" + try: + content = path.read_text() + + result = { + "name": path.stem, + "path": str(path.relative_to(CLAUDE_DIR)), + "description": "", + "model": "unknown", + "tools": [], + } + + # Parse YAML frontmatter + if content.startswith("---"): + parts = content.split("---", 2) + if len(parts) >= 2: + frontmatter = parts[1] + for line in frontmatter.strip().split("\n"): + if ":" in line: + key, value = line.split(":", 1) + key = key.strip() + value = value.strip() + if key == "name": + result["name"] = value + elif key == "description": + result["description"] = value + elif key == "model": + result["model"] = value + elif key == "tools": + result["tools"] = [t.strip() for t in value.split(",")] + + return result + + except Exception as e: + return {"name": path.stem, "error": str(e)} + + +def get_model_emoji(model: str) -> str: + """Get emoji for model type.""" + return { + "opus": "šŸ”·", + "sonnet": "šŸ”¶", + "haiku": "šŸ”ø" + }.get(model.lower(), "ā—‹") + + +def list_agents(): + """List all available agents.""" + registry = load_registry() + reg_agents = registry.get("agents", {}) + + print(f"\nšŸ¤– Available Agents ({len(reg_agents)})\n") + + # Group by model + by_model = {"opus": [], "sonnet": [], "haiku": [], "unknown": []} + + for name, info in reg_agents.items(): + model = info.get("model", "unknown") + by_model.get(model, by_model["unknown"]).append({ + "name": name, + "description": info.get("description", "No description"), + "triggers": info.get("triggers", []) + }) + + for model in ["opus", "sonnet", "haiku"]: + agents = by_model[model] + if not agents: + continue + + emoji = get_model_emoji(model) + print(f"=== {model.title()} {emoji} ===") + + for agent in sorted(agents, key=lambda a: a["name"]): + print(f" {agent['name']}") + print(f" {agent['description']}") + if agent['triggers']: + print(f" Triggers: {', '.join(agent['triggers'][:3])}") + + print("") + + +def show_tree(): + """Show agent hierarchy as a tree.""" + print(f"\n🌳 Agent Hierarchy\n") + + def print_tree(name: str, prefix: str = "", is_last: bool = True): + info = HIERARCHY.get(name, {}) + registry = load_registry() + reg_info = registry.get("agents", {}).get(name, {}) + model = reg_info.get("model", "?") + emoji = get_model_emoji(model) + + connector = "└── " if is_last else "ā”œā”€ā”€ " + print(f"{prefix}{connector}{name} {emoji} ({model})") + + new_prefix = prefix + (" " if is_last else "│ ") + subordinates = info.get("subordinates", []) + + for i, sub in enumerate(subordinates): + print_tree(sub, new_prefix, i == len(subordinates) - 1) + + # Start from root + print_tree("personal-assistant") + print("") + + print("Legend: šŸ”· opus šŸ”¶ sonnet šŸ”ø haiku") + print("") + + +def show_agent(name: str): + """Show details for a specific agent.""" + registry = load_registry() + reg_agents = registry.get("agents", {}) + + # Find matching agent + matches = [n for n in reg_agents.keys() if name.lower() in n.lower()] + + if not matches: + print(f"Agent '{name}' not found.") + print("\nAvailable agents:") + for n in sorted(reg_agents.keys()): + print(f" - {n}") + return + + if len(matches) > 1 and name not in matches: + print(f"Multiple matches for '{name}':") + for m in matches: + print(f" - {m}") + return + + agent_name = name if name in matches else matches[0] + reg_info = reg_agents[agent_name] + + print(f"\nšŸ¤– Agent: {agent_name}\n") + + model = reg_info.get("model", "unknown") + print(f"Model: {model} {get_model_emoji(model)}") + print(f"Description: {reg_info.get('description', 'No description')}") + + # Triggers + triggers = reg_info.get("triggers", []) + if triggers: + print(f"\nTriggers:") + for t in triggers: + print(f" - {t}") + + # Hierarchy + hier = HIERARCHY.get(agent_name, {}) + supervisor = hier.get("supervisor") + subordinates = hier.get("subordinates", []) + + print(f"\nHierarchy:") + if supervisor: + print(f" Supervisor: {supervisor}") + else: + print(f" Supervisor: (top-level)") + + if subordinates: + print(f" Subordinates:") + for sub in subordinates: + sub_info = reg_agents.get(sub, {}) + sub_model = sub_info.get("model", "?") + print(f" - {sub} ({sub_model})") + + # Check for agent file + agent_file = AGENTS_DIR / f"{agent_name}.md" + if agent_file.exists(): + print(f"\nFile: agents/{agent_name}.md") + file_info = parse_agent_md(agent_file) + if file_info.get("tools"): + print(f"Tools: {', '.join(file_info['tools'])}") + + print("") + + +def main(): + parser = argparse.ArgumentParser(description="Show agent information") + parser.add_argument("name", nargs="?", help="Agent name to show details") + parser.add_argument("--tree", "-t", action="store_true", + help="Show agent hierarchy tree") + parser.add_argument("--list", "-l", action="store_true", help="List all agents") + + args = parser.parse_args() + + if args.tree: + show_tree() + elif args.name and not args.list: + show_agent(args.name) + else: + list_agents() + + +if __name__ == "__main__": + main() diff --git a/automation/completions.bash b/automation/completions.bash index f6066ba..d5d5fef 100644 --- a/automation/completions.bash +++ b/automation/completions.bash @@ -51,6 +51,24 @@ _claude_upgrade() { COMPREPLY=($(compgen -W "--check --backup --apply --help" -- "${cur}")) } +_claude_workflow() { + local cur="${COMP_WORDS[COMP_CWORD]}" + + COMPREPLY=($(compgen -W "--category --list" -- "${cur}")) +} + +_claude_skill_info() { + local cur="${COMP_WORDS[COMP_CWORD]}" + + COMPREPLY=($(compgen -W "--scripts --list" -- "${cur}")) +} + +_claude_agent_info() { + local cur="${COMP_WORDS[COMP_CWORD]}" + + COMPREPLY=($(compgen -W "--tree --list" -- "${cur}")) +} + _claude_memory_add() { local cur="${COMP_WORDS[COMP_CWORD]}" local prev="${COMP_WORDS[COMP_CWORD-1]}" @@ -87,6 +105,9 @@ complete -F _claude_debug debug.sh complete -F _claude_export session-export.py complete -F _claude_mcp_status mcp-status.sh complete -F _claude_upgrade upgrade.sh +complete -F _claude_workflow workflow-info.py +complete -F _claude_skill_info skill-info.py +complete -F _claude_agent_info agent-info.py # Alias completions for convenience alias claude-validate='~/.claude/automation/validate-setup.sh' @@ -106,7 +127,11 @@ alias claude-debug='~/.claude/automation/debug.sh' alias claude-export='python3 ~/.claude/automation/session-export.py' alias claude-mcp='~/.claude/automation/mcp-status.sh' alias claude-upgrade='~/.claude/automation/upgrade.sh' +alias claude-workflow='python3 ~/.claude/automation/workflow-info.py' +alias claude-skill='python3 ~/.claude/automation/skill-info.py' +alias claude-agent='python3 ~/.claude/automation/agent-info.py' echo "Claude Code completions loaded. Available aliases:" -echo " claude-{validate,status,backup,restore,clean,memory-add,memory-list}" -echo " claude-{search,history,install,test,maintenance,log,debug,export,mcp,upgrade}" +echo " claude-{validate,status,backup,restore,clean,memory-add,memory-list,search}" +echo " claude-{history,install,test,maintenance,log,debug,export,mcp,upgrade}" +echo " claude-{workflow,skill,agent}" diff --git a/automation/completions.zsh b/automation/completions.zsh index d1a1ffc..5f1c9f2 100644 --- a/automation/completions.zsh +++ b/automation/completions.zsh @@ -107,6 +107,30 @@ _claude_upgrade() { '--help[Show help]' } +# Workflow completion +_claude_workflow() { + _arguments \ + '--category[Filter by category]:category:(health deploy incidents sysadmin)' \ + '--list[List all workflows]' \ + '*:name:' +} + +# Skill info completion +_claude_skill_info() { + _arguments \ + '--scripts[Show scripts in listing]' \ + '--list[List all skills]' \ + '*:name:' +} + +# Agent info completion +_claude_agent_info() { + _arguments \ + '--tree[Show hierarchy tree]' \ + '--list[List all agents]' \ + '*:name:' +} + # Register completions compdef _memory_add memory-add.py compdef _memory_list memory-list.py @@ -118,6 +142,9 @@ compdef _claude_debug debug.sh compdef _claude_export session-export.py compdef _claude_mcp_status mcp-status.sh compdef _claude_upgrade upgrade.sh +compdef _claude_workflow workflow-info.py +compdef _claude_skill_info skill-info.py +compdef _claude_agent_info agent-info.py # Aliases alias claude-validate='~/.claude/automation/validate-setup.sh' @@ -137,7 +164,11 @@ alias claude-debug='~/.claude/automation/debug.sh' alias claude-export='python3 ~/.claude/automation/session-export.py' alias claude-mcp='~/.claude/automation/mcp-status.sh' alias claude-upgrade='~/.claude/automation/upgrade.sh' +alias claude-workflow='python3 ~/.claude/automation/workflow-info.py' +alias claude-skill='python3 ~/.claude/automation/skill-info.py' +alias claude-agent='python3 ~/.claude/automation/agent-info.py' echo "Claude Code completions loaded (zsh)" -echo " Aliases: claude-{validate,status,backup,restore,clean,memory-add,memory-list}" -echo " claude-{search,history,install,test,maintenance,log,debug,export,mcp,upgrade}" +echo " Aliases: claude-{validate,status,backup,restore,clean,memory-add,memory-list,search}" +echo " claude-{history,install,test,maintenance,log,debug,export,mcp,upgrade}" +echo " claude-{workflow,skill,agent}" diff --git a/automation/skill-info.py b/automation/skill-info.py new file mode 100755 index 0000000..780a2d5 --- /dev/null +++ b/automation/skill-info.py @@ -0,0 +1,225 @@ +#!/usr/bin/env python3 +""" +Show information about available skills. +Usage: python3 skill-info.py [--scripts] [name] +""" + +import argparse +import json +import re +import sys +from pathlib import Path +from typing import Dict, List, Optional + +CLAUDE_DIR = Path.home() / ".claude" +SKILLS_DIR = CLAUDE_DIR / "skills" +REGISTRY_PATH = CLAUDE_DIR / "state" / "component-registry.json" + + +def load_registry() -> Dict: + """Load component registry.""" + try: + with open(REGISTRY_PATH) as f: + return json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + return {} + + +def find_skills() -> List[Path]: + """Find all skill directories with SKILL.md.""" + if not SKILLS_DIR.exists(): + return [] + + return [d for d in SKILLS_DIR.iterdir() + if d.is_dir() and (d / "SKILL.md").exists()] + + +def parse_skill_md(path: Path) -> Dict: + """Parse a SKILL.md file for metadata.""" + try: + content = path.read_text() + + result = { + "name": path.parent.name, + "path": str(path.relative_to(CLAUDE_DIR)), + "description": "", + "allowed_tools": [], + } + + # Parse YAML frontmatter + if content.startswith("---"): + parts = content.split("---", 2) + if len(parts) >= 2: + frontmatter = parts[1] + for line in frontmatter.strip().split("\n"): + if ":" in line: + key, value = line.split(":", 1) + key = key.strip() + value = value.strip() + if key == "description": + result["description"] = value + elif key == "allowed-tools": + result["allowed_tools"] = [t.strip() for t in value.split(",")] + + # Get first paragraph as description if not in frontmatter + if not result["description"]: + body = content.split("---")[-1] if "---" in content else content + lines = body.strip().split("\n\n") + for para in lines: + if para.strip() and not para.startswith("#"): + result["description"] = para.strip()[:200] + break + + return result + + except Exception as e: + return {"name": path.parent.name, "error": str(e)} + + +def get_skill_scripts(skill_dir: Path) -> List[str]: + """Get list of scripts in a skill's scripts/ directory.""" + scripts_dir = skill_dir / "scripts" + if not scripts_dir.exists(): + return [] + + scripts = [] + for f in scripts_dir.iterdir(): + if f.is_file() and f.suffix in [".py", ".sh"]: + scripts.append(f.name) + return sorted(scripts) + + +def get_skill_references(skill_dir: Path) -> List[str]: + """Get list of reference files in a skill's references/ directory.""" + refs_dir = skill_dir / "references" + if not refs_dir.exists(): + return [] + + refs = [] + for f in refs_dir.iterdir(): + if f.is_file(): + refs.append(f.name) + return sorted(refs) + + +def list_skills(show_scripts: bool = False): + """List all available skills.""" + registry = load_registry() + reg_skills = registry.get("skills", {}) + + skills = find_skills() + + if not skills: + print("No skills found.") + return + + print(f"\nšŸŽÆ Available Skills ({len(skills)})\n") + + for skill_dir in sorted(skills): + name = skill_dir.name + skill_info = parse_skill_md(skill_dir / "SKILL.md") + reg_info = reg_skills.get(name, {}) + + desc = skill_info.get("description", reg_info.get("description", "No description")) + if len(desc) > 80: + desc = desc[:77] + "..." + + print(f" {name}") + print(f" {desc}") + + if show_scripts: + scripts = get_skill_scripts(skill_dir) + if scripts: + print(f" Scripts: {', '.join(scripts)}") + + triggers = reg_info.get("triggers", []) + if triggers: + trigger_str = ", ".join(triggers[:4]) + if len(triggers) > 4: + trigger_str += f" (+{len(triggers)-4} more)" + print(f" Triggers: {trigger_str}") + + print("") + + +def show_skill(name: str): + """Show details for a specific skill.""" + # Find matching skill + skills = find_skills() + matches = [s for s in skills if name.lower() in s.name.lower()] + + if not matches: + print(f"Skill '{name}' not found.") + print("\nAvailable skills:") + for s in sorted(skills): + print(f" - {s.name}") + return + + if len(matches) > 1 and not any(s.name == name for s in matches): + print(f"Multiple matches for '{name}':") + for s in matches: + print(f" - {s.name}") + return + + skill_dir = next((s for s in matches if s.name == name), matches[0]) + skill_info = parse_skill_md(skill_dir / "SKILL.md") + + registry = load_registry() + reg_info = registry.get("skills", {}).get(skill_dir.name, {}) + + print(f"\nšŸŽÆ Skill: {skill_dir.name}\n") + print(f"Path: {skill_dir.relative_to(CLAUDE_DIR)}/") + print(f"Description: {skill_info.get('description', 'No description')}") + + # Allowed tools + allowed = skill_info.get("allowed_tools", []) + if allowed: + print(f"\nAllowed Tools: {', '.join(allowed)}") + + # Triggers + triggers = reg_info.get("triggers", []) + if triggers: + print(f"\nTriggers:") + for t in triggers: + print(f" - {t}") + + # Scripts + scripts = get_skill_scripts(skill_dir) + if scripts: + print(f"\nScripts:") + for s in scripts: + script_path = skill_dir / "scripts" / s + executable = "āœ“" if script_path.stat().st_mode & 0o111 else "ā—‹" + print(f" {executable} {s}") + + # References + refs = get_skill_references(skill_dir) + if refs: + print(f"\nReferences:") + for r in refs: + print(f" - {r}") + + # Registry script + if "script" in reg_info: + print(f"\nRegistry Script: {reg_info['script']}") + + print("") + + +def main(): + parser = argparse.ArgumentParser(description="Show skill information") + parser.add_argument("name", nargs="?", help="Skill name to show details") + parser.add_argument("--scripts", "-s", action="store_true", + help="Show scripts in listing") + parser.add_argument("--list", "-l", action="store_true", help="List all skills") + + args = parser.parse_args() + + if args.name and not args.list: + show_skill(args.name) + else: + list_skills(args.scripts) + + +if __name__ == "__main__": + main() diff --git a/automation/test-scripts.sh b/automation/test-scripts.sh index 8908c1f..885a16f 100755 --- a/automation/test-scripts.sh +++ b/automation/test-scripts.sh @@ -85,6 +85,27 @@ else fail "session-export.py syntax error" fi +# Test 10: workflow-info.py +if python3 -m py_compile "${AUTOMATION_DIR}/workflow-info.py" 2>/dev/null; then + pass "workflow-info.py syntax valid" +else + fail "workflow-info.py syntax error" +fi + +# Test 11: skill-info.py +if python3 -m py_compile "${AUTOMATION_DIR}/skill-info.py" 2>/dev/null; then + pass "skill-info.py syntax valid" +else + fail "skill-info.py syntax error" +fi + +# Test 12: agent-info.py +if python3 -m py_compile "${AUTOMATION_DIR}/agent-info.py" 2>/dev/null; then + pass "agent-info.py syntax valid" +else + fail "agent-info.py syntax error" +fi + echo "" echo "=== Skill Scripts ===" diff --git a/automation/workflow-info.py b/automation/workflow-info.py new file mode 100755 index 0000000..fdf99aa --- /dev/null +++ b/automation/workflow-info.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +""" +List and describe available workflows. +Usage: python3 workflow-info.py [--category CAT] [name] +""" + +import argparse +import json +import sys +from pathlib import Path +from typing import Dict, List, Optional +import yaml + +CLAUDE_DIR = Path.home() / ".claude" +WORKFLOWS_DIR = CLAUDE_DIR / "workflows" +REGISTRY_PATH = CLAUDE_DIR / "state" / "component-registry.json" + + +def load_registry() -> Dict: + """Load component registry.""" + try: + with open(REGISTRY_PATH) as f: + return json.load(f) + except (FileNotFoundError, json.JSONDecodeError): + return {} + + +def find_workflow_files() -> List[Path]: + """Find all workflow YAML files.""" + if not WORKFLOWS_DIR.exists(): + return [] + + files = [] + for pattern in ["*.yaml", "*.yml", "**/*.yaml", "**/*.yml"]: + files.extend(WORKFLOWS_DIR.glob(pattern)) + + # Filter out README and other non-workflow files + return [f for f in files if f.name not in ["README.md"]] + + +def parse_workflow(path: Path) -> Optional[Dict]: + """Parse a workflow YAML file.""" + try: + with open(path) as f: + content = f.read() + # Handle YAML front matter or full YAML + if content.startswith("---"): + parts = content.split("---", 2) + if len(parts) >= 2: + return yaml.safe_load(parts[1]) + return yaml.safe_load(content) + except Exception: + return None + + +def get_workflow_category(path: Path) -> str: + """Get workflow category from path.""" + rel_path = path.relative_to(WORKFLOWS_DIR) + if len(rel_path.parts) > 1: + return rel_path.parts[0] + return "general" + + +def list_workflows(category: Optional[str] = None): + """List all available workflows.""" + registry = load_registry() + workflows = registry.get("workflows", {}) + + # Group by category + categories: Dict[str, List] = {} + + for name, info in workflows.items(): + cat = name.split("/")[0] if "/" in name else "general" + if category and cat != category: + continue + + if cat not in categories: + categories[cat] = [] + + categories[cat].append({ + "name": name, + "description": info.get("description", "No description"), + "triggers": info.get("triggers", []) + }) + + if not categories: + print("No workflows found.") + return + + print(f"\nšŸ“‹ Available Workflows\n") + + for cat in sorted(categories.keys()): + print(f"=== {cat.title()} ===") + for wf in categories[cat]: + print(f" {wf['name']}") + print(f" {wf['description']}") + if wf['triggers']: + print(f" Triggers: {', '.join(wf['triggers'][:3])}") + print("") + + +def show_workflow(name: str): + """Show details for a specific workflow.""" + registry = load_registry() + workflows = registry.get("workflows", {}) + + # Find matching workflow + matches = [n for n in workflows.keys() if name in n] + + if not matches: + print(f"Workflow '{name}' not found.") + print("\nAvailable workflows:") + for n in sorted(workflows.keys()): + print(f" - {n}") + return + + if len(matches) > 1 and name not in matches: + print(f"Multiple matches for '{name}':") + for m in matches: + print(f" - {m}") + return + + wf_name = name if name in matches else matches[0] + wf_info = workflows[wf_name] + + print(f"\nšŸ“‹ Workflow: {wf_name}\n") + print(f"Description: {wf_info.get('description', 'No description')}") + + triggers = wf_info.get("triggers", []) + if triggers: + print(f"\nTriggers:") + for t in triggers: + print(f" - {t}") + + # Try to find and show the actual workflow file + possible_paths = [ + WORKFLOWS_DIR / f"{wf_name}.yaml", + WORKFLOWS_DIR / f"{wf_name}.yml", + WORKFLOWS_DIR / wf_name / "workflow.yaml", + ] + + for path in possible_paths: + if path.exists(): + wf_data = parse_workflow(path) + if wf_data: + print(f"\nFile: {path.relative_to(CLAUDE_DIR)}") + + if "steps" in wf_data: + print(f"\nSteps:") + for i, step in enumerate(wf_data["steps"], 1): + step_name = step.get("name", f"Step {i}") + agent = step.get("agent", "unknown") + print(f" {i}. {step_name} (agent: {agent})") + + if "trigger" in wf_data: + trigger = wf_data["trigger"] + if isinstance(trigger, dict): + if trigger.get("schedule"): + print(f"\nSchedule: {trigger['schedule']}") + if trigger.get("manual"): + print("Manual trigger: Yes") + break + + print("") + + +def main(): + parser = argparse.ArgumentParser(description="List and describe workflows") + parser.add_argument("name", nargs="?", help="Workflow name to show details") + parser.add_argument("--category", "-c", type=str, help="Filter by category") + parser.add_argument("--list", "-l", action="store_true", help="List all workflows") + + args = parser.parse_args() + + if args.name and not args.list: + show_workflow(args.name) + else: + list_workflows(args.category) + + +if __name__ == "__main__": + main() diff --git a/commands/README.md b/commands/README.md index b6d7b12..a4f1f00 100644 --- a/commands/README.md +++ b/commands/README.md @@ -19,6 +19,9 @@ Slash commands for quick actions. User-invoked (type `/command` to trigger). | `/debug` | `/diag`, `/diagnose` | Debug and troubleshoot config | | `/export` | `/session-export`, `/share` | Export session for sharing | | `/mcp-status` | `/mcp`, `/integrations` | Check MCP integrations | +| `/workflow` | `/workflows`, `/wf` | List and describe workflows | +| `/skill-info` | `/skill`, `/skills-info` | Show skill information | +| `/agent-info` | `/agent`, `/agents` | Show agent information | | `/maintain` | `/maintenance`, `/admin` | Configuration maintenance | | `/programmer` | | Code development tasks | | `/gcal` | `/calendar`, `/cal` | Google Calendar access | diff --git a/commands/agent-info.md b/commands/agent-info.md new file mode 100644 index 0000000..4ddcf3b --- /dev/null +++ b/commands/agent-info.md @@ -0,0 +1,36 @@ +--- +name: agent-info +description: Show information about available agents +aliases: [agent, agents] +invokes: command:agent-info +--- + +# Agent Info Command + +Show information about available agents and their hierarchy. + +## Usage + +``` +/agent-info # List all agents +/agent-info # Show agent details +/agent-info --tree # Show agent hierarchy +``` + +## Implementation + +Run the agent info script: + +```bash +python3 ~/.claude/automation/agent-info.py [options] [name] +``` + +## Output Includes + +| Field | Description | +|-------|-------------| +| Name | Agent identifier | +| Description | What the agent handles | +| Model | Assigned model (opus/sonnet/haiku) | +| Triggers | Keywords that route to this agent | +| Supervisor | Parent agent in hierarchy | diff --git a/commands/skill-info.md b/commands/skill-info.md new file mode 100644 index 0000000..7b00061 --- /dev/null +++ b/commands/skill-info.md @@ -0,0 +1,36 @@ +--- +name: skill-info +description: Show information about available skills +aliases: [skill, skills-info] +invokes: command:skill-info +--- + +# Skill Info Command + +Show detailed information about available skills. + +## Usage + +``` +/skill-info # List all skills +/skill-info # Show skill details +/skill-info --scripts # List skills with scripts +``` + +## Implementation + +Run the skill info script: + +```bash +python3 ~/.claude/automation/skill-info.py [options] [name] +``` + +## Output Includes + +| Field | Description | +|-------|-------------| +| Description | What the skill does | +| Scripts | Available executable scripts | +| Triggers | Keywords that invoke the skill | +| References | Documentation files | +| Allowed Tools | Tool restrictions (if any) | diff --git a/commands/workflow.md b/commands/workflow.md new file mode 100644 index 0000000..ad4d511 --- /dev/null +++ b/commands/workflow.md @@ -0,0 +1,40 @@ +--- +name: workflow +description: List and describe available workflows +aliases: [workflows, wf] +invokes: command:workflow +--- + +# Workflow Command + +List and describe available workflows. + +## Usage + +``` +/workflow # List all workflows +/workflow # Show workflow details +/workflow --category # Filter by category +``` + +## Implementation + +Run the workflow info script: + +```bash +python3 ~/.claude/automation/workflow-info.py [options] [name] +``` + +## Categories + +| Category | Examples | +|----------|----------| +| `health` | cluster-health-check, cluster-daily-summary | +| `deploy` | deploy-app | +| `incidents` | pod-crashloop, node-issue-response | +| `sysadmin` | health-check, system-update | + +## Note + +Workflows are design documents - they guide Claude's actions but aren't +auto-executed. Use this command to understand available procedures. diff --git a/state/component-registry.json b/state/component-registry.json index 9c428c8..3b7be9c 100644 --- a/state/component-registry.json +++ b/state/component-registry.json @@ -184,6 +184,21 @@ "description": "Check MCP integration status", "aliases": ["/mcp", "/integrations"], "invokes": "command:mcp-status" + }, + "/workflow": { + "description": "List and describe workflows", + "aliases": ["/workflows", "/wf"], + "invokes": "command:workflow" + }, + "/skill-info": { + "description": "Show skill information", + "aliases": ["/skill", "/skills-info"], + "invokes": "command:skill-info" + }, + "/agent-info": { + "description": "Show agent information", + "aliases": ["/agent", "/agents"], + "invokes": "command:agent-info" } }, "agents": { @@ -317,7 +332,11 @@ "debug": "~/.claude/automation/debug.sh", "daily-maintenance": "~/.claude/automation/daily-maintenance.sh", "session-export": "~/.claude/automation/session-export.py", - "mcp-status": "~/.claude/automation/mcp-status.sh" + "mcp-status": "~/.claude/automation/mcp-status.sh", + "upgrade": "~/.claude/automation/upgrade.sh", + "workflow-info": "~/.claude/automation/workflow-info.py", + "skill-info": "~/.claude/automation/skill-info.py", + "agent-info": "~/.claude/automation/agent-info.py" }, "completions": { "bash": "~/.claude/automation/completions.bash",