claude-skills/engineering/skills/runbook-generator/scripts/runbook_generator.py
Reza Rezvani 1851c8fb09 fix(plugins): restructure 9 multi-skill domain plugins into ./skills/ layout
Same root cause as #587/#591 — Claude Code's runtime loader rejects
array-form skills paths like ["./content-production", "./ai-seo", ...]
even when each entry is a valid subdirectory containing SKILL.md.
`claude plugin validate` accepts them but the loader does not.

The proven canonical layout (used by self-improving-agent in #536):

  <plugin>/
  ├── .claude-plugin/plugin.json    skills: "./skills"
  └── skills/
      ├── <skill-1>/SKILL.md
      ├── <skill-2>/SKILL.md
      └── ...

Restructured 9 multi-skill domain plugins:
- business-growth (4 skills moved)
- c-level-advisor (28)
- engineering (36)
- engineering-team (32)
- finance (2)
- marketing-skill (43)
- product-team (12)
- project-management (8)
- ra-qm-team (13)

Also fixed standalone plugins that had root SKILL.md + ./skills/ subdir
(agenthub, autoresearch-agent, executive-mentor, playwright-pro). The
loader rejected them despite skills="./skills" because of the conflicting
root SKILL.md (compare self-improving-agent which works because PR #536
moved its root SKILL.md). Moved each root SKILL.md into ./skills/<name>/.

Restored standalone plugin folders to their original paths after the
multi-skill restructure swept them into parent skills/ directories
(marketplace.json source paths require original locations).

Removed 7 orphaned marketplace entries that pointed to skill folders
without their own plugin.json (content-creator, demand-gen,
fullstack-engineer, aws-architect, product-manager, scrum-master,
skill-security-auditor) — these were already non-functional.

Bumped patch versions on every changed plugin and synced
marketplace.json. Marketplace now lists 29 working plugins (down
from 36).

After merge: users run `/plugin marketplace update claude-code-skills`
followed by `/plugin update --all` to pick up the working layout.
2026-05-02 22:51:20 +02:00

128 lines
2.8 KiB
Python
Executable file

#!/usr/bin/env python3
"""Generate an operational runbook skeleton for a service."""
from __future__ import annotations
import argparse
from datetime import date
from pathlib import Path
def build_runbook(service: str, owner: str, environment: str) -> str:
today = date.today().isoformat()
return f"""# Runbook - {service}
- Service: {service}
- Owner: {owner}
- Environment: {environment}
- Last verified: {today}
## Overview
Describe the service purpose, dependencies, and critical user impact.
## Preconditions
- Access to deployment platform
- Access to logs/metrics
- Access to secret/config manager
## Start Procedure
1. Pull latest config/secrets.
2. Start service process.
3. Confirm process is healthy.
```bash
# Example
# systemctl start {service}
```
## Stop Procedure
1. Drain traffic if applicable.
2. Stop service process.
3. Confirm no active workers remain.
```bash
# Example
# systemctl stop {service}
```
## Health Checks
- HTTP health endpoint
- Dependency connectivity checks
- Error-rate and latency checks
```bash
# Example
# curl -sf https://{service}.example.com/health
```
## Deployment Checklist
1. Verify CI status and artifact integrity.
2. Apply migrations (if required) in safe order.
3. Deploy service revision.
4. Run smoke checks.
5. Observe metrics for 10-15 minutes.
## Rollback
1. Identify last known good release.
2. Re-deploy previous version.
3. Re-run health checks.
4. Communicate rollback status to stakeholders.
```bash
# Example
# deployctl rollback --service {service}
```
## Incident Response
1. Classify severity.
2. Contain user impact.
3. Triage likely failing component.
4. Escalate if SLA risk is high.
## Escalation
- L1: On-call engineer
- L2: Service owner ({owner})
- L3: Platform/Engineering leadership
## Post-Incident
1. Write timeline and root cause.
2. Define corrective actions with owners.
3. Update this runbook with missing steps.
"""
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description="Generate a markdown runbook skeleton.")
parser.add_argument("service", help="Service name")
parser.add_argument("--owner", default="platform-team", help="Service owner label")
parser.add_argument("--environment", default="production", help="Primary environment")
parser.add_argument("--output", help="Optional output path (prints to stdout if omitted)")
return parser.parse_args()
def main() -> int:
args = parse_args()
markdown = build_runbook(args.service, owner=args.owner, environment=args.environment)
if args.output:
path = Path(args.output)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(markdown, encoding="utf-8")
print(f"Wrote runbook skeleton to {path}")
else:
print(markdown)
return 0
if __name__ == "__main__":
raise SystemExit(main())