diff --git a/.claude/skills/debug-service/SKILL.md b/.claude/skills/debug-service/SKILL.md new file mode 100644 index 0000000..5f2b869 --- /dev/null +++ b/.claude/skills/debug-service/SKILL.md @@ -0,0 +1,107 @@ +--- +name: debug-service +description: Debug a service in this compose collection — read its compose definition, pull deploy status and logs from Coolify, check out the matching upstream source into sources/, and prove the root cause before changing the service directory. Use when a service here fails to deploy, crashes, or misbehaves. Not for bugs in the upstream project's own code or in repos outside this collection. +--- + +# Debug a service + +Find why one service in this repository fails, with evidence, and fix it in +that service's directory. Prove the cause before editing anything; stop +investigating as soon as it is proven. + +## Boundaries + +- Read `/.env.example`, never `/.env`; it holds real secrets. + Do not copy tokens, passwords or keys from logs into reports. +- Read-only Coolify calls need no confirmation. `control` (start, stop, + restart) and `deploy` affect a live service: ask the user first. +- Never commit anything under `sources/`, and never fix a service by editing + upstream code there. + +## 1. Frame the issue + +Name the service directory (`/`), the observed symptom and the +expected behaviour. If the user did not name the service, match the symptom +against the root `README.md` table. + +## 2. Read the local definition + +Read `/compose.yml`, `/README.md`, `/.env.example`, +and `/Dockerfile` with any files it copies. For each container note +the image and tag (or the Dockerfile's `FROM`), environment variable names, +volumes and command. + +Run `git log --oneline -10 -- /`; a recent change is the first suspect. + +## 3. Collect runtime evidence + +Coolify has two MCP servers, `miti-jp` and `miti-sg`; the service may live on +either. + +1. `search_resources` with the service name on both servers. +2. For a failed deploy: `list_deployments`, then `get_deployment` with + `include_log_summary=true`. +3. `get_logs` only when the resource is running; otherwise follow the + returned reason and `next_tools` rather than retrying. +4. `list_env_keys` to confirm every variable in `.env.example` is set + (names only; values are never returned). + +If neither server has it, the service is likely on Dokploy, which has no MCP +here: ask the user to paste the container logs and deploy output. + +Keep the exact error lines; they are the search keys for step 5. If the logs +and compose definition already prove the cause (a missing variable, a wrong +path), skip to step 6. + +## 4. Check out the upstream source + +Pick the repositories that matter: + +- `image:` services: the image's upstream repo, found from the registry page, + the image's `org.opencontainers.image.source` label, or the service README. +- `build: .` services: the Dockerfile in the service directory is local code; + also take the `FROM` image's repo, and for a wrapper image (linuxserver, + for example) the application repo it packages, if the error comes from it. +- Closed-source images have no repo. Say so and work from logs and vendor + docs only. + +Resolve the version the container runs. Use an exact tag directly. For a +moving tag (`latest`, `:4`), take the version printed in the logs; failing +that, the latest release (`gh release view -R / --json tagName`), +and say it is inferred. + +Clone into `sources//`: + +```sh +git clone --depth 1 --branch https://github.com// sources// +``` + +If the checkout exists, switch it instead of cloning again: + +```sh +git -C sources// fetch --depth 1 origin tag +git -C sources// checkout +``` + +## 5. Trace the cause + +- Search the checkout for the exact error text, the failing config key, or + the environment variable name. +- Read how the code consumes that variable, path or flag, and compare it with + what `compose.yml` and the Dockerfile provide. +- When it looks like a regression, check the upstream changelog and issues + for that version. + +State the cause with evidence: the log line, the source file and line, and +the mismatch with the service definition. If evidence is inconclusive, report +the hypotheses and what would distinguish them instead of guessing a fix. + +## 6. Fix and report + +Change only `/`, following this repository's `CLAUDE.md`: comments +say *what*, reasons go in the service `README.md`, `.env.example` stays in sync +and in compose order. Pin an exact version only when the newer release is +proven broken, and write what breaks in the README. + +Report the cause, the evidence, the change, and how to verify after redeploy. +Ask before redeploying. Leave `sources/` checkouts in place for next time. diff --git a/.gitignore b/.gitignore index 3620350..57c27ad 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,7 @@ desktop.ini *.swp .idea/ .vscode/ + +# Upstream source checkouts for debugging; only the directory itself is kept +sources/* +!sources/.gitkeep diff --git a/CLAUDE.md b/CLAUDE.md index 9356f84..ed177d5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -113,9 +113,13 @@ Reordering a compose file means reordering the `.env.example` with it. ## Deployment target -Services are deployed through Coolify and Dokploy, not plain `docker compose` -on a host. The platform owns the parts a standalone compose file would declare -itself. +Services are deployed through Coolify, not plain `docker compose` on a host. +The platform owns the parts a standalone compose file would declare itself. + +Coolify is the primary target: design, test and debug against it first. +Dokploy is optional — keep a service working there when it costs nothing +(the `restart:` policy below), but never trade Coolify behaviour for Dokploy +compatibility, and do not block on Dokploy-only issues. ## Intentional omissions — do not "fix" these @@ -155,3 +159,11 @@ Compose interpolation reads the deploying shell's environment before the already exports. `HOSTNAME` is the trap: it is set inside every container, including the one Coolify itself runs in, and would silently win. Hence `SERVICE_HOSTNAME` in `code-server` and `paseo`. + +## Upstream sources + +`sources/` is for upstream source checkouts used while debugging, cloned as +`sources//` at the version the service runs. Its contents are +gitignored; only `sources/.gitkeep` is tracked. Never commit a checkout or fix +a service by editing code there. Use the `debug-service` skill +(`.claude/skills/debug-service/SKILL.md`) for service issues. diff --git a/README.md b/README.md index eebe850..3eb42f9 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ My docker compose collection — one directory per service, each self-contained. Tuned to my own setup rather than written as general-purpose templates. -Services are deployed through [Coolify](https://coolify.io) and -[Dokploy](https://dokploy.com), which own what a standalone compose file would -otherwise declare: +Services are deployed through [Coolify](https://coolify.io), with +[Dokploy](https://dokploy.com) supported as an optional extra. The platform +owns what a standalone compose file would otherwise declare: - **No published ports.** The platform attaches the container to its proxy network and maps a domain to the internal port. Publishing one would also @@ -37,6 +37,13 @@ and are not repeated or linked from a service, so editing one service never touches another's directory — each is a separate Coolify app deploying on a `/**` watch path. +## Upstream sources + +`sources/` holds checkouts of the upstream repositories behind these images, +cloned as `sources//` when a service needs debugging against its +real code. Only the empty directory is tracked; its contents are gitignored. +The `debug-service` skill in `.claude/skills/` walks through the process. + ## Usage In Coolify or Dokploy, point a Docker Compose resource at the service directory diff --git a/sources/.gitkeep b/sources/.gitkeep new file mode 100644 index 0000000..e69de29