diff --git a/.claude/commands/CREDITS b/.claude/commands/CREDITS deleted file mode 100644 index 06b79f71..00000000 --- a/.claude/commands/CREDITS +++ /dev/null @@ -1,9 +0,0 @@ -Authors and sources of commands -=============================== - -- plan-python.md -- implement-python.md - -Source: Cole Medin, https://github.com/coleam00/context-engineering-intro (MIT License) - ---- diff --git a/.claude/commands/implement-container-deployment.md b/.claude/commands/implement-container-deployment.md index 94ffa78f..5e6b0fd6 100644 --- a/.claude/commands/implement-container-deployment.md +++ b/.claude/commands/implement-container-deployment.md @@ -8,25 +8,52 @@ INSTALL_INSTRUCTIONS_FILE: $ARGUMENTS Deploy a container-based service by creating and configuring a Docker Compose file. Use the application details and deployment instructions from the file: INSTALL_INSTRUCTIONS_FILE -Follow closely the architectural patterns described in the `docker/guidelines.md` file. +This file is the PRP produced by `/plan-container-deployment`. Follow closely the architectural +patterns described in the `docker/guidelines.md` file. -### Part 1 - Create Docker Compose file +### Part 1 - Create the Docker Compose file -- Read the `docker/guidelines.md` file for the architectural patterns you must follow. -- Read the INSTALL_INSTRUCTIONS_FILE file and use its content to create the compose file in the required structure. Abort if the file is not specified or does not exist. +- Read the `docker/guidelines.md` file for the architectural patterns you must follow. In particular note the **"Template for New Services"** section — use it as the starting skeleton. +- Read the INSTALL_INSTRUCTIONS_FILE and use its content to create the compose file. **Abort if the file is not specified or does not exist.** +- From the PRP, note the metadata you will need later: `Application name`, `Category`, `Homepage`, `GitHub page`, `Dashboard Icon`, `Dashboard Group`, `Short description`, `Long description`. These are consumed by the header comment and the labels below — do not discard them. - If the installation instructions contain steps to fetch the Compose setup and/or environment variables from a git repository: - - Shallow clone that repository to /tmp/infra/container// and look at the referenced compose and .env files there. - - Use the compose and .env files without any changes. - - If there are additional configuration files, which are referenced in the compose file, copy them. + - Shallow clone that repository to `/tmp/infra/container//` and look at the referenced compose and `.env` files there. + - Use the compose and `.env` files without any changes. + - If there are additional configuration files referenced in the compose file, copy them. - Keep the cloned repository. - For each container image used in the deployment, get the most specific tag (e.g. tag "1.2.0" is more specific than "1.2") by using the `get-most-specific-container-tag` MCP tool. Use the tag(s) returned by the tool in the Compose stack. -- Based on these patterns and the found examples on the installation instructions page, create the Docker Compose file and save it as `docker///.yaml`. -- Ensure the compose file contains a brief description of the project and links to the homepage, GitHub page, and any Docker or Docker Compose setup example (if available). -- If the installation guide suggests enhancements (e.g., using an optional external database instead of a built-in one, or enabling SSO), add TODOs at the top of the compose file. -- If any new environment variables are required for configuration, add them to the `config-example/docker/myhost/.env` file with placeholder values only (do not commit secrets). - -### Part 2 - Finishing steps - -- After writing the compose file, run `pre-commit run --files ` and resolve any reported issues. -- Validate the compose file with `scripts/labctl.py service config /` and fix any errors or warnings. -- Pull the container image(s) with the command `scripts/labctl.py service pull / --quiet` (with 15 minutes timeout) and verify success. +- Save the Docker Compose file as `docker///.yaml`, where `` is the `Category` from the PRP. +- **Header comment.** Start the file with the comment block from the guidelines template: the `Long description`, then a `Links:` list (Homepage, GitHub/Source, Docs, and any Docker/Compose setup example), then a `TODO:` line. +- **Networking.** Connect the service to the shared external `proxy` network by default. For sensitive services (password managers, backup, VPN, anything holding secrets), use an isolated network instead, per the "Isolated Networks" section of the guidelines — and add a `TODO` reminding the user that Traefik must be joined to that new network (in `docker/security/traefik/traefik.yaml`). +- **Traefik labels.** If the service has a web UI, expose it via Traefik labels (`traefik.enable`, the router `Host(...)` rule, the loadbalancer server port, and the access middleware). Choose the access middleware explicitly and state your choice in the summary: + - `localaccess@file` — local network only (default) + - `localaccess-sso@file` — local network + Authelia authentication + - `publicaccess@file` — reachable externally with CrowdSec protection +- **Homepage dashboard labels.** Add the dashboard labels using the PRP metadata: `homepage.group` = `Dashboard Group`, `homepage.name` = `Application name`, `homepage.icon` = `Dashboard Icon`, `homepage.href` = the service URL, `homepage.description` = `Short description`. +- If the installation guide suggests enhancements (e.g. using an optional external database instead of a built-in one, or enabling SSO), add them as `TODO` lines in the header comment. +- **Environment variables.** Reuse the existing common variables (`TIMEZONE`, `PUID`, `PGID`, `MYDOMAIN`, `DOCKER_VOLUMES`) — they are already defined, do not redefine them. For any *new* variable the service needs, add it with a **placeholder value only (never a real secret)** to the correct `.env` example file, following the precedence in the guidelines: + - Common, non-secret, same for every host → `config-example/docker/.env` + - Host-specific values or secrets/API keys → `config-example/docker/myhost/.env` (the usual case for a new service) + +#### AMD GPU acceleration (only if the PRP says the app supports it) + +If the PRP's research indicates the application supports AMD GPU acceleration (VAAPI for video decode/transcode, or ROCm for compute/inference), create a **separate compose override file** for it following the **"GPU Acceleration Overrides"** section of `docker/guidelines.md` — do not put GPU config in the base compose file. Name it `docker///-amdgpu.yaml`, include only the changed fields, and make its header comment record any manual in-app steps the PRP identified. + +### Part 2 - Register the service + +A compose file alone is **not** deployable — the service must be registered so `labctl.py` / `task docker:apply` discovers it. + +- Add the service to `config-example/docker/myhost/services.yaml`. The file's `services:` key holds a list of single-key category blocks (e.g. `- ai:`, `- tools:`, `- media/video:`); find the block matching its `` and append the entry to that block's list. Create a new `- :` block only if one does not already exist. Use: + ```yaml + - name: + state: up + ``` +- Keep the entries within a category grouped together and consistent with the existing formatting. + +### Part 3 - Finishing steps + +- Run `pre-commit run --files ` and resolve any reported issues. +- Validate the compose file with `scripts/labctl.py service config /` and fix any errors or warnings (this confirms env-var interpolation resolves). +- Pull the container image(s) with `scripts/labctl.py service pull / --quiet` (with a 15 minute timeout) and verify success. +- **If any of these steps still fails after a couple of fix attempts, stop and report the exact error to the user** rather than guessing further or leaving the repo half-changed. +- Finish with a short summary: the file path created, the category/dashboard group used, the access middleware chosen, any new env vars added (and to which file), and any `TODO`s left for the user (e.g. joining Traefik to a new isolated network). diff --git a/.claude/commands/implement-python.md b/.claude/commands/implement-python.md deleted file mode 100644 index a7896989..00000000 --- a/.claude/commands/implement-python.md +++ /dev/null @@ -1,40 +0,0 @@ -# Implement Python application - Execute PRP - -Implement a feature using the PRP file. - -## PRP File: $ARGUMENTS - -## Execution Process - -1. **Load PRP** - - Read the specified PRP file - - Understand all context and requirements - - Follow all instructions in the PRP and extend the research if needed - - Ensure you have all needed context to implement the PRP fully - - Do more web searches and codebase exploration as needed - -2. **ULTRATHINK** - - Think hard before you execute the plan. Create a comprehensive plan addressing all requirements. - - Break down complex tasks into smaller, manageable steps using your todos tools. - - Use the TodoWrite tool to create and track your implementation plan. - - Identify implementation patterns from existing code to follow. - -3. **Execute the plan** - - Execute the PRP - - Implement all the code - -4. **Validate** - - Run each validation command - - Fix any failures - - Re-run until all pass - -5. **Complete** - - Ensure all checklist items are done - - Run final validation suite - - Report completion status - - Read the PRP again to ensure you have implemented everything - -6. **Reference the PRP** - - You can always reference the PRP again if needed - -Note: If validation fails, use the error patterns described in the PRP to fix and retry. diff --git a/.claude/commands/improve-github-workflows.md b/.claude/commands/improve-github-workflows.md index 5c51f22f..48dfd980 100644 --- a/.claude/commands/improve-github-workflows.md +++ b/.claude/commands/improve-github-workflows.md @@ -4,10 +4,19 @@ description: Analyze GitHub Actions workflows and recommend improvements for spe Analyze the GitHub Actions workflows in this repository and provide recommendations for improving pipeline execution speed and efficiency. -**IMPORTANT: Token Management** -- Use small batch sizes for all GitHub API calls to avoid exceeding token limits -- Be selective: analyze the most important workflows in detail, others only at a high level -- Get targeted data: use specific API calls for individual runs rather than listing many runs +**This command only analyzes and reports — do not edit any workflow files.** Show before/after code in the report; leave applying changes to the user. + +**Preflight (do this first, abort if it fails):** +This command uses the GitHub CLI (`gh`) for all run data. Verify it is available and authenticated: +```bash +gh --version # must exist on PATH +gh auth status # must report a logged-in account with repo/actions access +``` +If `gh` is not installed or `gh auth status` fails, **stop and tell the user**: report exactly what failed and how to fix it (install `gh`, or run `gh auth login`). Do not attempt `gh auth login` yourself and do not fall back to unauthenticated API calls — without run data this command cannot do its job. + +`gh` infers the repository from the git remote; add `-R /` only if the wrong repo is picked up. + +**Token management:** request only the JSON fields you need (`--json ...`), limit runs to a handful (`--limit 5`), and use `--log-failed` rather than pulling full logs. Follow these steps: @@ -16,19 +25,20 @@ Follow these steps: - Read each workflow file to understand the structure - If there are more than 5 workflows, prioritize the most critical ones (CI, deployments) for detailed analysis -2. **Analyze recent workflow executions**: - - Use `mcp__github__list_workflows` to get workflow IDs - - For each workflow, use `mcp__github__list_workflow_runs` to get recent runs (use parameter: perPage=3) - - Focus on the most frequently run workflows first - - Use `mcp__github__get_workflow_run` to get details for 1-2 representative runs per workflow - - Use `mcp__github__list_workflow_jobs` to examine job execution (use parameter: perPage=10) - - Use `mcp__github__get_job_logs` with `failed_only: true` to identify common failure patterns - - Analyze execution times, bottlenecks, and patterns across runs +2. **Analyze recent workflow executions** (via `gh`): + - List workflows: `gh workflow list` + - For each workflow, get recent runs (timing + status): + `gh run list --workflow --limit 5 --json databaseId,status,conclusion,createdAt,updatedAt,event` + - Focus on the most frequently run workflows first. + - For 1-2 representative runs, get per-job/step timings: + `gh run view --json jobs` (each job has `startedAt`/`completedAt` and a `steps` array with the same) + - For failing runs, inspect only the failed logs: `gh run view --log-failed` + - Compute execution times from the `startedAt`/`completedAt` timestamps; look for bottlenecks and patterns across runs. 3. **Examine workflow configuration**: - Job dependencies and sequencing - Matrix strategies - - Caching configuration (actions/cache, Docker layer caching, etc.) + - Caching configuration (actions/cache, Docker layer caching, etc.) — note what caching **already exists** so you don't recommend adding caching a job already has - Concurrency settings - Conditional execution - Runner types (ubuntu-latest, self-hosted, etc.) diff --git a/.claude/commands/plan-container-deployment.md b/.claude/commands/plan-container-deployment.md index 25ee56df..285c0f1d 100644 --- a/.claude/commands/plan-container-deployment.md +++ b/.claude/commands/plan-container-deployment.md @@ -2,13 +2,18 @@ ## Variables -APPLICATION_NAME: $ARGUMENTS -INSTALL_INSTRUCTIONS_URL: $ARGUMENTS +$ARGUMENTS contains both of the following; split it as described: +- INSTALL_INSTRUCTIONS_URL: the token that looks like a URL (starts with `http`). +- APPLICATION_NAME: the remaining text. If only a URL was given, derive the name from the URL / the page's title once fetched. + +If `$ARGUMENTS` is empty or no URL can be identified, ask the user for the application name and the installation-instructions URL before continuing. ## Instructions Your task is to collect all necessary know-how for deploying a containerized application using Docker Compose. +**First, check the application is not already deployed:** use the `get-container-categories` MCP tool and/or run `find docker -iname '**'`. If a matching service already exists, stop and tell the user rather than producing a duplicate PRP. + ### Part 1 - Look for installation details Visit the installation instructions page for APPLICATION_NAME at INSTALL_INSTRUCTIONS_URL and search for Docker Compose deployment examples in this priority order: @@ -18,6 +23,7 @@ Visit the installation instructions page for APPLICATION_NAME at INSTALL_INSTRUC 3. Plain docker setup (`docker run ...`) Gather all information relevant to container deployment. +Also research whether the application supports **AMD GPU acceleration** — e.g. VAAPI for video decode/transcode or ROCm for compute/inference. Note the type of acceleration, whether the vendor ships a GPU-specific image tag, and any manual in-app configuration it requires. Record findings only; do not design the compose files here (that is done in the implementation step). ABORT your work if no container-based installation method is found. ### Part 2 - Gather application metadata @@ -48,7 +54,7 @@ Long description: + ``` diff --git a/.claude/commands/plan-python.md b/.claude/commands/plan-python.md deleted file mode 100644 index 723339d6..00000000 --- a/.claude/commands/plan-python.md +++ /dev/null @@ -1,69 +0,0 @@ -# Plan development of Python application - Create PRP - -## Feature file: $ARGUMENTS - -Generate a complete PRP for general feature implementation with thorough research. Ensure context is passed to the AI agent to enable self-validation and iterative refinement. Read the feature file first to understand what needs to be created, how the examples provided help, and any other considerations. - -The AI agent only gets the context you are appending to the PRP and training data. Assume the AI agent has access to the codebase and the same knowledge cutoff as you, so its important that your research findings are included or referenced in the PRP. The Agent has Websearch capabilities, so pass urls to documentation and examples. - -## Research Process - -1. **Codebase Analysis** - - Search for similar features/patterns in the codebase - - Identify files to reference in PRP - - Note existing conventions to follow - - Check test patterns for validation approach - -2. **External Research** - - Search for similar features/patterns online - - Library documentation (include specific URLs) - - Implementation examples (GitHub/StackOverflow/blogs) - - Best practices and common pitfalls - -3. **User Clarification** (if needed) - - Specific patterns to mirror and where to find them? - - Integration requirements and where to find them? - -## PRP Generation - -Using docs/PRPs/templates/prp-python.md as template: - -### Critical Context to Include and pass to the AI agent as part of the PRP -- **Documentation**: URLs with specific sections -- **Code Examples**: Real snippets from codebase -- **Gotchas**: Library quirks, version issues -- **Patterns**: Existing approaches to follow - -### Implementation Blueprint -- Start with pseudocode showing approach -- Reference real files for patterns -- Include error handling strategy -- list tasks to be completed to fulfill the PRP in the order they should be completed - -### Validation Gates (Must be Executable) eg for python -```bash -# Syntax/Style -ruff check --fix && mypy . - -# Unit Tests -uv run pytest tests/ -v - -``` - -*** CRITICAL AFTER YOU ARE DONE RESEARCHING AND EXPLORING THE CODEBASE BEFORE YOU START WRITING THE PRP *** - -*** ULTRATHINK ABOUT THE PRP AND PLAN YOUR APPROACH THEN START WRITING THE PRP *** - -## Output -Save as: `docs/PRPs/{feature-name}.md` - -## Quality Checklist -- [ ] All necessary context included -- [ ] Validation gates are executable by AI -- [ ] References existing patterns -- [ ] Clear implementation path -- [ ] Error handling documented - -Score the PRP on a scale of 1-10 (confidence level to succeed in one-pass implementation using claude codes) - -Remember: The goal is one-pass implementation success through comprehensive context. diff --git a/.claude/commands/update-ai-models.md b/.claude/commands/update-ai-models.md index 68b02d3b..233bcffe 100644 --- a/.claude/commands/update-ai-models.md +++ b/.claude/commands/update-ai-models.md @@ -45,7 +45,7 @@ For each model in the config, decide: - **Keep (previous)**: One version behind the latest → keep as-is (allows pinning to the prior version) - **Remove**: Two or more versions behind the latest → remove to avoid clutter -Example: config has Opus 4.5 and 4.6 → Opus 4.7 released → add 4.7, keep 4.6, remove 4.5. +Example (illustrates the rule — do not treat these version numbers as current): config has Opus 4.5 and 4.6 → Opus 4.7 released → add 4.7, keep 4.6, remove 4.5. Apply the "latest / one-behind / two-or-more-behind" rule against the versions you actually find in Step 1, not against the numbers written here or already in the config. Preserve without changes: - The overall YAML structure, comments, and provider groupings @@ -62,30 +62,33 @@ Update both the `docker exec ollama ollama pull ` lines and the inline co ### LiteLLM Ollama entries sync -After updating the Taskfile, update the `ollama-local-*` entries in `config.yaml` to match: -- `ollama_chat/` must reflect the exact tag used in the pull script +After updating the Taskfile, make the `ollama-local-*` entries in `config.yaml` match it **one-to-one**: there must be exactly one `ollama-local-*` entry per model pulled by the task. If the task pulls a model that has no matching entry, **add** the missing entry; if an entry points to a model no longer pulled, remove it. +- **Chat models** (the ≤3B and ≤8B entries): `ollama_chat/` must reflect the exact tag used in the pull script. +- **Embedding models** (e.g. `nomic-embed-text`): use the `ollama/:latest` prefix, not `ollama_chat/` — LiteLLM routes `ollama_chat/` to the chat-completions endpoint, which doesn't serve embeddings. E.g. `ollama/nomic-embed-text:latest`. - Update the comment line above each entry (e.g. `# Local model - Phi 4 Mini (3.8B)`) - Do **not** change `api_base` or `api_key` references +- **Out of scope:** entries that are not produced by the task, e.g. `ollama-mac-mistral` (a remote Mac's Ollama via `REMOTE_OLLAMA_API_BASE`). Leave these untouched. ## Step 3: Update the files -Write the updated LiteLLM config using: -```bash -tee "$(git rev-parse --show-toplevel)/docker/ai/litellm/config/config.yaml" > /dev/null << 'EOF' - -EOF -``` - -Update the `get-offline-data-ollama` task in `Taskfile.yaml` directly using the Edit tool. +Edit `docker/ai/litellm/config/config.yaml` and `Taskfile.yaml` with the **Edit tool**, making targeted, minimal changes — one edit per model entry added/removed/renamed. Do **not** rewrite either file wholesale (a full-file rewrite risks silently dropping comments, provider groupings, or the inline doc links). -Also update `router_settings.fallbacks` in `config.yaml` to reflect any renamed models. +Also update `router_settings.fallbacks` in `config.yaml`: +- Reflect any **renamed** model names, and +- **Remove** any fallback entry that points to a model you removed in Step 2, so no fallback references a model that no longer exists in the config. ## Step 4: Verify -Confirm the LiteLLM config was written correctly: -```bash -docker exec litellm cat /app/config.yaml -``` +1. Lint the changed files: `pre-commit run --files docker/ai/litellm/config/config.yaml Taskfile.yaml` and fix any issues (the repo lints YAML with yamllint). +2. Restart LiteLLM so it re-reads and **parses** the new config, then confirm it came up cleanly (a YAML or unknown-model error surfaces here, not from re-reading the file): + ```bash + scripts/labctl.py service restart ai/litellm + docker logs litellm --tail 50 2>&1 | grep -i "error\|invalid\|traceback" || echo "no startup errors" + ``` +3. Confirm the running container sees the intended config: + ```bash + docker exec litellm cat /app/config.yaml + ``` ## LiteLLM model ID format reference @@ -95,7 +98,8 @@ docker exec litellm cat /app/config.yaml | OpenAI (direct) | `openai/` | | Google Gemini (direct) | `gemini/` | | OpenRouter | `openrouter//` | -| Ollama (local) | `ollama_chat/` | +| Ollama (local, chat) | `ollama_chat/` | +| Ollama (local, embed) | `ollama/:latest` | Example: `openrouter/meta-llama/llama-4-maverick`, `anthropic/claude-sonnet-4-6` diff --git a/.claude/skills/debug-container-service/SKILL.md b/.claude/skills/debug-container-service/SKILL.md index d35914e4..5568649a 100644 --- a/.claude/skills/debug-container-service/SKILL.md +++ b/.claude/skills/debug-container-service/SKILL.md @@ -21,6 +21,24 @@ Make sure you have: The compose file is at `docker///.yaml`. If the user mentions an error but not the service name, ask. If the service is obvious from context, proceed. +If you know the service name but not its `category`, look it up instead of guessing: list categories with the `mcp__infra-mcp__get-container-categories` MCP tool, or run `find docker -name '.yaml'`. + +**Scope.** This skill covers container/compose-level problems. If the root cause turns out to be host-level — host firewall, DNS, storage/permissions on a mount, Proxmox networking, or a down dependency host (e.g. a remote NAS) — stop patching the container, state that clearly, and hand the host-level fix back to the user. + +--- + +## Step 0 — Confirm the Service Exists and Is Running + +Before analysing logs, confirm the container is actually deployed and running — an empty log stream from a container that never started is a different problem. + +```bash +docker ps -a --filter "name=" --format '{{.Names}}\t{{.Status}}' +``` + +- **Not listed at all** → the service was never started. Check it is registered in `config/docker//services.yaml` with `state: up`, then bring it up (`scripts/labctl.py service up category/service-name`). +- **`Restarting` / `Exited`** → it is crash-looping. The logs (Step 2) will contain the startup error; this is expected, proceed. +- **`Up`** → running but misbehaving; proceed normally. + --- ## Step 1 — Get Compose Config and Identify Services @@ -37,7 +55,7 @@ From the config, identify: - **Environment variables** (may reveal misconfiguration) - **Image tag** (needed for source code lookups in Steps 4–7) -Environment variables are loaded from `.env` files in this precedence order (later overrides earlier): +Environment variables are loaded from `.env` files in this precedence order (later overrides earlier; canonical reference: `docker/guidelines.md` → "Environment Variables Management"): 1. `config/docker/.env` — common to all hosts 2. `config/docker//.env` — host-specific 3. `config/docker/.env.` — service-specific (all hosts) @@ -114,6 +132,8 @@ Use the GitHub API to read the actual source for the version in use: gh api repos///contents/?ref= --jq '.content' | base64 -d | grep -i "" ``` +> The `gh`-based steps (4–7) need an authenticated CLI. If a `gh` call fails with an auth or rate-limit error, run `gh auth status` — if unauthenticated, ask the user to run `gh auth login` (do not attempt it yourself), and meanwhile fall back to Context7 docs and web search. + --- ## Step 5 — Search GitHub Issues @@ -149,7 +169,11 @@ gh api repos///releases --jq '.[0:5] | .[] | {tag: .tag_name, body: . **Upgrading:** If a newer version contains the fix, update the image tag in the service YAML file (`docker/category/service/service.yaml`) and recreate the container. -**Downgrading:** If a recent update introduced the regression, note the last known-good version and offer to roll back. +**Downgrading:** If a recent update introduced the regression, note the last known-good version, set the image tag in the service YAML back to it, and recreate the container: +```bash +scripts/labctl.py service recreate category/service-name +``` +Then re-check the logs (Step 2) and tell the user the version was pinned, so the regression can be reported upstream. --- diff --git a/docker/guidelines.md b/docker/guidelines.md index ef5598dd..9cf29707 100644 --- a/docker/guidelines.md +++ b/docker/guidelines.md @@ -25,6 +25,8 @@ networks: external: true ``` +Each service file lives at `docker///.yaml`, where `` is one of the subfolders under `docker/` (e.g. `ai`, `tools`, `media/video`). + **Common Practices:** - Service metadata at the top with comments for documentation - Links to official sites, source repositories, and helpful guides @@ -206,6 +208,44 @@ Under the hood, these tasks use the `docker compose` command with the following docker compose -f "$yaml_file" --env-file "$env_file" up --detach ``` +### Service Registration + +A compose file is not deployed until the service is registered in the host's `config/docker//services.yaml`, listed under its `` with `state: up` (or `down`). `task docker:apply` / `labctl.py` only act on registered services. + +### Managing Individual Services (`labctl.py`) + +Services are addressed as `/` (e.g. `ai/ollama`, `media/video/jellyfin`). Manage a single service with: + +```bash +scripts/labctl.py service / +``` + +Operations: `up`, `down`, `restart`, `recreate`, `pull`, `config` (render the resolved compose config), `logs`. + +## GPU Acceleration Overrides + +Services that support hardware acceleration keep the GPU configuration in a **separate Docker Compose override file** — never in the base compose file, so hosts without a GPU run the base file unchanged. + +- The override file is named `docker///-.yaml` (e.g. `-amdgpu`). `labctl.py` merges it automatically when the host sets `GPU_COMPOSE_SUFFIX=` in `config/docker//.env`. +- Because it is a merge override, it repeats the same `name:` and service key as the base file and includes **only the fields that change**. + +```yaml +# AMD GPU override (VAAPI video decode/transcode, or ROCm compute) +--- +name: service-name +services: + service-name: + # image: vendor/service:tag-rocm # only if the vendor ships a GPU-specific tag (e.g. Ollama :rocm) + devices: + - /dev/dri/renderD128:/dev/dri/renderD128 # VAAPI / render node + # - /dev/kfd:/dev/kfd # add for ROCm compute (inference); not needed for VAAPI-only + group_add: + - "${GPU_RENDER_GID}" # render group — numeric GID required (name may not exist in container) + - "${GPU_VIDEO_GID}" # video group +``` + +The override's header comment must state which acceleration it provides, the `GPU_COMPOSE_SUFFIX=` enable line, and any **manual in-app steps** still required (e.g. Jellyfin: enable VA-API in Dashboard → Playback → Transcoding; Frigate: set `hwaccel_args: preset-vaapi` in `config/config.yml`). See the working examples: `docker/media/video/jellyfin/jellyfin-amdgpu.yaml`, `docker/ai/ollama/ollama-amdgpu.yaml`, `docker/security/frigate/frigate-amdgpu.yaml`. + ## Service Categories Services are organized into logical categories: diff --git a/docs/PRPs/templates/prp-python.md b/docs/PRPs/templates/prp-python.md deleted file mode 100644 index 9dab24e8..00000000 --- a/docs/PRPs/templates/prp-python.md +++ /dev/null @@ -1,212 +0,0 @@ -name: "Base PRP Template v2 - Context-Rich with Validation Loops" -description: | - -## Purpose -Template optimized for AI agents to implement features with sufficient context and self-validation capabilities to achieve working code through iterative refinement. - -## Core Principles -1. **Context is King**: Include ALL necessary documentation, examples, and caveats -2. **Validation Loops**: Provide executable tests/lints the AI can run and fix -3. **Information Dense**: Use keywords and patterns from the codebase -4. **Progressive Success**: Start simple, validate, then enhance -5. **Global rules**: Be sure to follow all rules in CLAUDE.md - ---- - -## Goal -[What needs to be built - be specific about the end state and desires] - -## Why -- [Business value and user impact] -- [Integration with existing features] -- [Problems this solves and for whom] - -## What -[User-visible behavior and technical requirements] - -### Success Criteria -- [ ] [Specific measurable outcomes] - -## All Needed Context - -### Documentation & References (list all context needed to implement the feature) -```yaml -# MUST READ - Include these in your context window -- url: [Official API docs URL] - why: [Specific sections/methods you'll need] - -- file: [path/to/example.py] - why: [Pattern to follow, gotchas to avoid] - -- doc: [Library documentation URL] - section: [Specific section about common pitfalls] - critical: [Key insight that prevents common errors] - -- docfile: [docs/PRPs/ai_docs/file.md] - why: [docs that the user has pasted in to the project] - -``` - -### Current Codebase tree (run `tree` in the root of the project) to get an overview of the codebase -```bash - -``` - -### Desired Codebase tree with files to be added and responsibility of file -```bash - -``` - -### Known Gotchas of our codebase & Library Quirks -```python -# CRITICAL: [Library name] requires [specific setup] -# Example: FastAPI requires async functions for endpoints -# Example: This ORM doesn't support batch inserts over 1000 records -# Example: We use Pydantic v2; be mindful of v1→v2 changes (e.g., BaseModel usage, model_validate, field validators) -``` - -## Implementation Blueprint - -### Data models and structure - -Create the core data models, we ensure type safety and consistency. -```python -Examples: - - orm models - - pydantic models - - pydantic schemas - - pydantic validators - -``` - -### list of tasks to be completed to fulfill the PRP in the order they should be completed - -```yaml -Task 1: -MODIFY src/existing_module.py: - - FIND pattern: "class OldImplementation" - - INJECT after line containing "def __init__" - - PRESERVE existing method signatures - -CREATE src/new_feature.py: - - MIRROR pattern from: src/similar_feature.py - - MODIFY class name and core logic - - KEEP error handling pattern identical - -...(...) - -Task N: -... - -``` - - -### Per-task pseudocode to be added to each task -```python - -# Task 1 -# Pseudocode with CRITICAL details dont write entire code -async def new_feature(param: str) -> Result: - # PATTERN: Always validate input first (see src/validators.py) - validated = validate_input(param) # raises ValidationError - - # GOTCHA: This library requires connection pooling - async with get_connection() as conn: # see src/db/pool.py - # PATTERN: Use existing retry decorator - @retry(attempts=3, backoff=exponential) - async def _inner(): - # CRITICAL: API returns 429 if >10 req/sec - await rate_limiter.acquire() - return await external_api.call(validated) - - result = await _inner() - - # PATTERN: Standardized response format - return format_response(result) # see src/utils/responses.py -``` - -### Integration Points -```yaml -DATABASE: - - migration: "Add column 'feature_enabled' to users table" - - index: "CREATE INDEX idx_feature_lookup ON users(feature_id)" - -CONFIG: - - add to: config/settings.py - - pattern: "FEATURE_TIMEOUT = int(os.getenv('FEATURE_TIMEOUT', '30'))" - -ROUTES: - - add to: src/api/routes.py - - pattern: "router.include_router(feature_router, prefix='/feature')" -``` - -## Validation Loop - -### Level 1: Syntax & Style -```bash -# Run these FIRST - fix any errors before proceeding -ruff check src/new_feature.py --fix # Auto-fix what's possible -mypy src/new_feature.py # Type checking - -# Expected: No errors. If errors, READ the error and fix. -``` - -### Level 2: Unit Tests each new feature/file/function use existing test patterns -```python -# CREATE test_new_feature.py with these test cases: -def test_happy_path(): - """Basic functionality works""" - result = new_feature("valid_input") - assert result.status == "success" - -def test_validation_error(): - """Invalid input raises ValidationError""" - with pytest.raises(ValidationError): - new_feature("") - -def test_external_api_timeout(): - """Handles timeouts gracefully""" - with mock.patch('external_api.call', side_effect=TimeoutError): - result = new_feature("valid") - assert result.status == "error" - assert "timeout" in result.message -``` - -```bash -# Run and iterate until passing: -uv run pytest test_new_feature.py -v -# If failing: Read error, understand root cause, fix code, re-run (never mock to pass) -``` - -### Level 3: Integration Test -```bash -# Start the service -uv run python -m src.main --dev - -# Test the endpoint -curl -X POST http://localhost:8000/feature \ - -H "Content-Type: application/json" \ - -d '{"param": "test_value"}' - -# Expected: {"status": "success", "data": {...}} -# If error: Check logs at logs/app.log for stack trace -``` - -## Final validation Checklist -- [ ] All tests pass: `uv run pytest tests/ -v` -- [ ] No linting errors: `uv run ruff check src/` -- [ ] No type errors: `uv run mypy src/` -- [ ] Manual test successful: [specific curl/command] -- [ ] Error cases handled gracefully -- [ ] Logs are informative but not verbose -- [ ] Documentation updated if needed - ---- - -## Anti-Patterns to Avoid -- ❌ Don't create new patterns when existing ones work -- ❌ Don't skip validation because "it should work" -- ❌ Don't ignore failing tests - fix them -- ❌ Don't use sync functions in async context -- ❌ Don't hardcode values that should be config -- ❌ Don't catch all exceptions - be specific