- FastAPI backend with SQLite (ai.db) - Tables: skills, snippets, conventions, cache, memory - MCP servers: homelab, gameservers, skills - Docker Compose setup - Seed data with 8 skills, 2 conventions, 2 snippets - Token savings patterns via context bundles and caching
221 lines
7.5 KiB
Python
221 lines
7.5 KiB
Python
#!/usr/bin/env python3
|
|
"""Seed the skills database with useful defaults"""
|
|
|
|
import httpx
|
|
|
|
BASE_URL = "http://localhost:8080"
|
|
|
|
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://localhost:8080/docs")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
seed()
|