#!/usr/bin/env python3 """Seed the skills database with useful defaults""" import httpx BASE_URL = "http://helm:8675" SKILLS = [ { "id": "homelab-docker-compose", "name": "Docker Compose Standard", "category": "homelab", "description": "Standard Docker Compose configuration patterns", "content": """Always use docker-compose v3.8+. Include: - health checks for all services - restart: unless-stopped policy - resource limits (memory, CPU) - named volumes for persistent data - .env file for secrets (never hardcode) - explicit network definitions - logging driver with size limits""", "tags": ["docker", "compose", "infrastructure"] }, { "id": "homelab-traefik", "name": "Traefik Reverse Proxy", "category": "homelab", "description": "Traefik configuration standards", "content": """For Traefik reverse proxy setups: - Use Docker provider with watched containers - Enable ACME/Let's Encrypt for HTTPS - Store certs in persistent volume - Use middlewares for auth, rate limiting, redirects - Label-based routing on containers - Dashboard protected by auth middleware""", "tags": ["traefik", "proxy", "https", "infrastructure"] }, { "id": "typescript-react", "name": "React TypeScript Component", "category": "coding", "description": "Standard React component patterns with TypeScript", "content": """React component standards: - Use functional components with TypeScript interfaces - Props defined as interface, not type alias - Use React.FC only when children needed - Prefer composition over inheritance - Custom hooks for reusable logic - Strict null checks enabled - Avoid any, use unknown if needed""", "tags": ["react", "typescript", "frontend"] }, { "id": "python-async", "name": "Python Async Patterns", "category": "coding", "description": "Async/await best practices in Python", "content": """Python async standards: - Use async/await consistently, don't mix sync/async - Use asyncio.gather() for concurrent operations - Proper exception handling in async contexts - Use async context managers (async with) - Avoid blocking calls in async functions - Use httpx over requests for async HTTP - Timeout all async operations""", "tags": ["python", "async", "asyncio"] }, { "id": "api-design", "name": "REST API Design", "category": "coding", "description": "RESTful API design patterns", "content": """API design standards: - Use nouns for resources, not verbs - Proper HTTP methods (GET/POST/PUT/DELETE) - Return appropriate status codes - Version APIs (/api/v1/) - Use query params for filtering, sorting - Pagination with limit/offset or cursor - Consistent error response format - Rate limiting headers""", "tags": ["api", "rest", "backend"] }, { "id": "valheim-server", "name": "Valheim Server Setup", "category": "gameserver", "description": "Valheim dedicated server configuration", "content": """Valheim server standards: - Run in Docker with persistent volumes - Backup world files regularly - Set -public 0 for private servers - Configure admin list properly - Monitor RAM usage (2-4GB typical) - Use server sync for crossplay - Restart nightly for memory leaks""", "tags": ["valheim", "gaming", "docker"] }, { "id": "minecraft-server", "name": "Minecraft Server Setup", "category": "gameserver", "description": "Minecraft server configuration patterns", "content": """Minecraft server standards: - Use PaperMC for performance - Pre-generate world chunks - Configure view-distance appropriately (6-10) - Use Aikar's flags for JVM optimization - Regular backups with rotation - Whitelist for private servers - Monitor TPS and chunk loading""", "tags": ["minecraft", "gaming", "java"] }, { "id": "git-commits", "name": "Git Commit Standards", "category": "coding", "description": "Commit message conventions", "content": """Commit message format: - Conventional Commits (feat:, fix:, chore:, etc.) - Imperative mood ("add feature" not "added feature") - First line max 50 chars - Blank line before body - Body wraps at 72 chars - Reference issues/PRs when applicable""", "tags": ["git", "workflow", "documentation"] } ] CONVENTIONS = [ { "id": "home-server-conventions", "project_path": "/opt/home-server", "name": "Home Server Standards", "content": """All home server deployments: - Docker Compose for all services - Traefik for reverse proxy - Health checks on all containers - Centralized logging - Automated backups - Resource limits defined""", "auto_inject": True } ] SNIPPETS = [ { "id": "docker-healthcheck", "name": "Docker Health Check Template", "language": "yaml", "category": "docker", "content": """healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 3 start_period: 40s""", "tags": ["docker", "health", "template"] }, { "id": "traefik-labels", "name": "Traefik Docker Labels", "language": "yaml", "category": "docker", "content": """labels: - "traefik.enable=true" - "traefik.http.routers.myapp.rule=Host(`myapp.example.com`)" - "traefik.http.routers.myapp.entrypoints=websecure" - "traefik.http.routers.myapp.tls.certresolver=letsencrypt" - "traefik.http.services.myapp.loadbalancer.server.port=8080""", "tags": ["traefik", "labels", "template"] } ] def seed(): with httpx.Client(timeout=30.0) as client: print("Seeding skills...") for skill in SKILLS: try: response = client.post(f"{BASE_URL}/skills", json=skill) if response.status_code == 200: print(f" ✓ {skill['id']}") elif response.status_code == 400: print(f" ~ {skill['id']} (already exists)") else: print(f" ✗ {skill['id']}: {response.text}") except Exception as e: print(f" ✗ {skill['id']}: {e}") print("\nSeeding conventions...") for convention in CONVENTIONS: try: response = client.post(f"{BASE_URL}/conventions", json=convention) if response.status_code == 200: print(f" ✓ {convention['id']}") elif response.status_code == 400: print(f" ~ {convention['id']} (already exists)") else: print(f" ✗ {convention['id']}: {response.text}") except Exception as e: print(f" ✗ {convention['id']}: {e}") print("\nSeeding snippets...") for snippet in SNIPPETS: try: response = client.post(f"{BASE_URL}/snippets", json=snippet) if response.status_code == 200: print(f" ✓ {snippet['id']}") elif response.status_code == 400: print(f" ~ {snippet['id']} (already exists)") else: print(f" ✗ {snippet['id']}: {response.text}") except Exception as e: print(f" ✗ {snippet['id']}: {e}") print("\nDone! Check http://helm:8675/docs") if __name__ == "__main__": seed()