Files

26 KiB

Tool index — catálogo canónico de herramientas

Este es el índice único de todo lo ejecutable del repo. Si buscas "qué script uso para X", empieza aquí y no en los TOOLS.md de cada skill (esos son guías de uso; este es el catálogo).

Verificado contra el host real el 2026-08-07. Las firmas de parámetros se extrajeron del AST de PowerShell, no a mano.


0. Cómo leer este índice

  • R/W — RO = solo lectura, se puede ejecutar sin preguntar. W = muta estado, exige confirmación explícita del usuario antes de ejecutar. RO/W = depende de los parámetros (columna "notas" lo aclara).
  • Env — variables que deben estar cargadas (. .\.env.local.ps1). Si faltan, el script lanza excepción, no falla silenciosamente.
  • Todo se ejecuta desde la raíz del repo, en PowerShell.

1. Los 6 gotchas que producen resultados silenciosamente incorrectos

Léelos antes de invocar nada. No son teóricos: los cuatro primeros se verificaron el 2026-08-07 y el quinto el 2026-08-23. Cada uno rompe una tarea de forma que parece haber funcionado.

1.1 -Raw significa lo OPUESTO en dos familias de wrappers

Hay dos convenciones incompatibles. Elegir mal no da error: da un resultado vacío.

Wrapper Sin -Raw (default) Con -Raw
coolify_skill\scripts\Invoke-CoolifyApi.ps1 string JSON objetos PowerShell
scripts\Invoke-CloudflareApi.ps1 string JSON objetos PowerShell
deploy_skill\scripts\Invoke-GitHubApi.ps1 objetos PowerShell {Status, Headers, Body}
gitea_skill\scripts\Invoke-GiteaApi.ps1 objetos PowerShell {Status, Headers, Body}

Consecuencia práctica: en Coolify y Cloudflare, si vas a filtrar o proyectar el resultado necesitas -Raw. Sin él recibes un System.String y

# MAL: devuelve una fila vacía, sin error. El resultado es un string.
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/resources" |
    Select-Object name, uuid

# BIEN
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/resources" -Raw |
    Select-Object name, uuid

Usa el default (string JSON) solo cuando vas a mostrar la respuesta tal cual.

1.2 Invoke-ProxmoxSsh.ps1 corrompe las comillas anidadas

Invoke-ProxmoxSshCommand pasa $Command como un único argumento a ssh, y PowerShell 5.1 destroza las comillas embebidas al invocar un ejecutable nativo. Cualquier comando con quoting anidado —típicamente docker exec ... bash -lc '... psql -c "SELECT ..."'— llega mutilado al host:

bash: line 1: -c: command not found
psql: option requires an argument -- 'F'

Solución verificada: codifica el comando remoto en base64. Es el patrón a usar para cualquier cosa con más de un nivel de comillas:

$remote = @'
pct exec 102 -- docker exec -i postgres-c11xzy2tx2cdapm32f5b89vy bash -lc 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -At -c "SELECT name FROM public.installation_configs"'
'@
$b64 = [Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes($remote))
.\scripts\Invoke-ProxmoxSsh.ps1 -Command "echo $b64 | base64 -d | bash 2>&1"

El here-string @'...'@ (comillas simples) es obligatorio: evita que PowerShell expanda $POSTGRES_PASSWORD del lado de Windows.

Para comandos de un solo nivel de comillas (pct list, docker ps --format '{{.Names}}') el wrapper directo funciona bien.

1.3 Los nombres de contenedor NO se pueden adivinar

Coolify nombra cada contenedor <servicio>-<uuid> (y a veces le añade un sufijo numérico de build). No existe un contenedor llamado chatwoot ni nextcloud:

chatwoot-c11xzy2tx2cdapm32f5b89vy
nextcloud-db-hdcdpkm0jko3qqvn5683ercc
web-instademo0portal0insta0demo1-060825532589

Siempre resuelve el nombre real antes de usarlo. Dos caminos:

# a) desde Docker, por patrón
.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker ps --format '{{.Names}}' | grep -i chatwoot"

# b) desde Coolify, para obtener el uuid del recurso (y de ahí el sufijo)
.\coolify_skill\scripts\Invoke-CoolifyApi.ps1 -Path "/resources" -Raw |
    Where-Object { $_.name -match 'chatwoot' } | Select-Object name, uuid, fqdn

Corolario: un redeploy puede recrear el contenedor con otro sufijo, y cualquier script o cron que tenga el nombre hardcodeado empieza a fallar. Es exactamente lo que le pasó al guard de Chatwoot (ver runbooks/chatwoot-update.md).

1.4 /applications/* da 404 — por Cloudflare, no por Coolify (corregido 2026-08-29)

Re-verificado a fondo el 2026-08-29 sobre v4.3.14 y el diagnóstico anterior cambió: el 404 NO lo produce Coolify. Es un bloqueo del edge de Cloudflare en el hostname público. Mismo token, misma ruta:

Llamada Resultado
https://coolify.urieljareth.org/api/v1/applications (vía Cloudflare) 404
http://192.168.0.117:8000/api/v1/applications (origen, LXC 102) 200
/github-apps igual: 404 vía CF, 200 vía origen
/version, /resources, /services, /databases, /projects, /servers, /teams, /deployments, /security/keys OK por ambas vías

La API del origen está completa: el openapi.yaml del contenedor (/var/www/html/openapi.yaml) declara todo el namespace de /applications/*, notificaciones, proveedores cloud y MCP, y responde. Para esos endpoints, apunta la llamada al origen ($env:COOLIFY_API_URL_ORIGIN) o corrige la regla de Cloudflare en el dashboard. Además, desde v4.2 los endpoints de estado exigen POST (GET /deploy → 405; ver notas §10.1).

Esto re-habilita (previa verificación en el próximo deploy) herramientas que estaban marcadas rotas — ver §4.

Nota (2026-08-24): POST /services sí funciona para stacks compose propios, con tres condiciones que la API no perdona: no enviar type junto a docker_compose_raw, mandar el compose en base64, y enviar el body como bytes UTF-8. Las tres estaban mal en el toolkit y ya están corregidas; el detalle está en docs/casos/firecrawl-stack-minimo.md §4. Test-PreDeployChecklist.ps1 sigue sin leer docker-compose.coolify.yml (solo mira docker-compose.yml|yaml y compose.yml|yaml), así que puede dar todo PASS sobre un archivo que no abrió.

1.5 "Verde en Coolify" NO significa "enrutado en Traefik"

Verificado el 2026-08-23. Es la causa de que un servicio recién creado desde la librería de Coolify devuelva 503 no available server estando en verde.

Son dos señales distintas y la UI solo muestra una:

Señal Quién la usa Qué significa
State.Status = running La UI de Coolify (el punto verde) El contenedor existe y no ha muerto
State.Health.Status = healthy Traefik El contenedor entra al balanceador

Traefik solo enruta contenedores que Docker reporta healthy. Un contenedor running + unhealthy no tiene ruta, la petición cae al catch-all de Coolify (default_redirect_503.yaml: priority: -1000, servicio noop con servers: { }) y de ahí sale el string no available server.

En este host el primer boot de un servicio tarda minutos (rootfs ext4 sobre loopback sobre HDD, ~39 ms por escritura), pero 12 de los 14 servicios no tienen start_period en su healthcheck. Se les declara unhealthy mucho antes de que la app llegue a escuchar.

Distingue el código HTTP antes de tocar nada:

  • 502 Bad Gateway → Traefik tiene la ruta, el backend rechaza. Problema de la app o del puerto.
  • 503 no available server → Traefik no tiene la ruta. Casi siempre es un contenedor que todavía está arrancando. Espera, no redeployes: un redeploy reinicia el entrypoint desde cero y reinicia el arranque lento.
# El diagnóstico correcto, en un comando (solo lectura):
.\coolify_skill\scripts\Test-CoolifyServiceReady.ps1 -Uuid <uuid> -WaitSeconds 600

Detalle completo, evidencia e hipótesis descartadas: docs/casos/coolify-servicio-nuevo-503-no-available-server.md.

1.6 Si la imagen no expone el puerto donde sirve, el FQDN necesita :puerto

Verificado el 2026-08-24 diagnosticando grimmory, que devolvía 502.

Coolify deriva el label traefik.http.services.*.loadbalancer.server.port del puerto que lleve el FQDN guardado en service_applications.fqdn. Si el FQDN no lleva puerto, Coolify no emite el label, y Traefik cae al único puerto que declare la imagen (Config.ExposedPorts).

Eso funciona por accidente cuando app e imagen coinciden, y falla en silencio cuando no:

Servicio FQDN guardado Sirve en Imagen expone Resultado
nextcloud sin puerto 80 80 OK por coincidencia
n8n …:5678 5678 5678 OK explícito
qdrant …:6333 6333 6333 OK explícito
grimmory sin puerto 80 6060 502

grimmory corría healthy (su healthcheck prueba http://127.0.0.1/health, o sea el 80, y pasaba), Traefik lo enrutaba, y llegaba al 6060 donde no hay nada: connection refused → 502.

Ojo con la confusión: tener SERVICE_URL_GRIMMORY_80 en el compose no basta. Lo que manda es el puerto en el FQDN almacenado.

Cómo distinguirlo de otros fallos:

  • 502 → hay ruta, el backend rechaza. Compara el puerto donde escucha la app con el que busca Traefik. Casi siempre es esto.
  • 503 no available server → no hay ruta (§1.5).
# Puertos donde escucha de verdad (en hex; 0050 = 80, 1F90 = 8080):
.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker exec <cont> sh -c 'cat /proc/net/tcp'"

# Puerto que busca Traefik (si no sale nada, cae al ExposedPorts de la imagen):
.\scripts\Invoke-ProxmoxSsh.ps1 -Command "pct exec 102 -- docker inspect <cont> --format '{{json .Config.Labels}}'"

Arreglo: poner el puerto en el FQDN (https://x.urieljareth.org:80) y redeployar el servicio — los labels solo se regeneran al recrear el contenedor.


2. Infraestructura: host Proxmox, red, apps del host

Todo llega al host por un solo camino:

PowerShell → Invoke-ProxmoxSshCommand → ssh [email protected]
           → pct exec 102 -- docker ...      (para cualquier cosa de Docker)
Script R/W Env Parámetros Qué hace
scripts/ProxmoxAgent.ps1 librería — — Dot-source obligatorio (. .\scripts\ProxmoxAgent.ps1). Expone Get-ProxmoxConfig, Assert-ProxmoxConfig, Invoke-ProxmoxSshCommand, Invoke-ProxmoxApi. Todos los demás scripts lo consumen; no reimplementes la conexión.
scripts/Test-ProxmoxConnection.ps1 RO opcional PROXMOX_API_TOKEN_* — Smoke test: config + SSH + muestra de Docker + auth de API. Sale 1 si algo falla. Ejecútalo antes de trabajo operativo.
scripts/Get-ProxmoxInventory.ps1 RO — — Snapshot completo: host, LXC, QEMU, Docker en LXC 102.
scripts/Invoke-ProxmoxSsh.ps1 RO/W — -Command <string> Comando arbitrario por SSH. El R/W lo determina el comando: pct list es RO, pct stop es W. Ver gotcha §1.2 para comillas anidadas.
scripts/Invoke-CloudflareApi.ps1 RO/W CLOUDFLARE_API_TOKEN -Method -Path -BodyJson -Raw API de Cloudflare (túnel + DNS). GET es RO; el resto W. -Raw → objetos (§1.1).
scripts/Install-CoolifyAutostart.ps1 W (RO con -VerifyOnly) — -VerifyOnly -SkipOnboot -RunNow -Uninstall Instala el auto-arranque del stack tras corte de luz (LXC 102 + túnel). Usa -VerifyOnly para auditar sin tocar nada.

API REST de Proxmox (distinta de la de Coolify): requiere PROXMOX_API_TOKEN_ID + PROXMOX_API_TOKEN_SECRET. Invoke-ProxmoxApi lanza excepción si faltan.

⚠️ Estado actual (2026-08-07): .env.local.ps1 no define PROXMOX_API_TOKEN_ID/_SECRET, CLOUDFLARE_API_TOKEN ni COOLIFY_EMAIL/COOLIFY_PASSWORD. Las tres rutas que dependen de ellas (API de Proxmox, API de Cloudflare, flujo UI de Coolify) fallan hoy. Lo que sí está cargado: PROXMOX_HOST/NODE/USER/SSH_KEY/COOLIFY_LXC, COOLIFY_API_URL, COOLIFY_TOKEN, GITHUB_TOKEN, GITHUB_OWNER, GITEA_URL/USER/TOKEN.

2.1 Chatwoot — parche enterprise

Contexto completo en runbooks/chatwoot-update.md.

Script R/W Parámetros Qué hace
scripts/Get-ChatwootLicenseStatus.ps1 RO -ServiceUuid -AppContainer -DbContainer -Deep Estado de la licencia. -Deep verifica además los feature flags por cuenta (accounts.feature_flags). Usa esto para diagnosticar; nunca el parche.
scripts/Apply-ChatwootEnterprisePatch.ps1 W -DryRun -ReenableAccountFeatures -ServiceUuid -Container -AppContainer -LxcId -ProxmoxHost -SshKey Reaplica el parche. El SQL de 3 filas no basta: pasa siempre -ReenableAccountFeatures. Usa -DryRun primero.
scripts/chatwoot-enterprise-guard.sh — — Copia versionada del guard que corre en el host. No se ejecuta desde Windows. Instalado en /root/scripts/chatwoot-enterprise-guard.sh, agendado por /etc/cron.d/chatwoot-enterprise-guard cada 5 min. Log: /var/log/chatwoot-enterprise-guard.log (solo escribe cuando actúa).

2.2 Artefactos que viven en el host (no se invocan desde Windows)

Archivo Qué es
scripts/host/coolify-autostart.sh Script de arranque; lo despliega Install-CoolifyAutostart.ps1.
scripts/host/coolify-autostart.service Unit de systemd correspondiente.
scripts/fix-nextcloud-config.php Fragmento puntual del fix HTTPS de Nextcloud. Ver runbooks/nextcloud.md.
scripts/Set-ProxmoxEnv.example.ps1 Plantilla de entorno. El template completo es .env.example.

2.3 Scripts de deploy específicos de una app

scripts/apps/ guarda scripts one-off con uuid y dominio hardcodeados. Son mutantes y están atados a un recurso concreto: lee la cabecera antes de ejecutar uno, y verifica que el uuid siga siendo el correcto (§1.3).

Script R/W Env Qué hace
scripts/apps/Deploy-SoloLeveling.ps1 W COOLIFY_*, PROXMOX_*, GITHUB_TOKEN (scope repo) Re-deploy de "El Sistema (Solo Leveling)" sin depender del pull de GHCR (el registry es privado y el token no tiene read:packages). Construye la imagen en el servidor (clone del repo privado + docker build), la taguea con el nombre que espera el compose generado por Coolify, y levanta el servicio. Params: -ServiceUuid -Domain -Repo -Image -NoBuild. Requiere que el service ya esté registrado en Coolify.
scripts/apps/Deploy-OhDaddy.ps1 W COOLIFY_*, PROXMOX_* Redeploy de oh-daddy (stack app+db+Inngest self-hosted, servicio rzittzudkunwx8gilonn7tqe). Clone del repo público + stacks/oh-daddy/Dockerfile inyectado, build de oh-daddy-app:local en el server, compose up -d, schema idempotente y re-registro de funciones Inngest (PUT /api/inngest). Params: -ServiceUuid -Fqdn -Repo -Image -NoBuild. Detalle: casos/oh-daddy-deploy.md.

3. Coolify — operación

Script R/W Env Parámetros Qué hace
coolify_skill/scripts/Get-CoolifyDockerStatus.ps1 RO — -Filter <regex> -All Estado de contenedores vía LXC 102. -All lista todo; -Filter acota por regex. Primera parada para "¿está corriendo X?".
coolify_skill/scripts/Test-CoolifyServiceReady.ps1 RO — -Uuid <uuid> -Fqdn <url> -WaitSeconds <n> Contrasta running vs healthy por contenedor (la discrepancia que la UI esconde), avisa de start_period insuficiente, detecta setup en curso (chown/apt) y prueba el dominio distinguiendo 503 de 502. Primera parada para un 503 no available server — ver §1.5.
coolify_skill/scripts/Set-CoolifyHealthcheckGrace.ps1 RO/W — -Uuid <uuid> -StartPeriodSeconds 300 -MinIntervalSeconds 10 -ShowResult -Apply Inserta start_period en los healthcheck que no lo tienen y sube intervalos demasiado cortos, editando services.docker_compose_raw. Dry-run sin -Apply. Con -Apply guarda copia de rollback en backups/ y verifica leyendo de vuelta. No redeploya — el healthcheck solo aplica al recrear el contenedor. Ver §1.5.
coolify_skill/scripts/Invoke-CoolifyApi.ps1 RO/W COOLIFY_TOKEN -Method -Path -BodyJson -Raw API de Coolify. GET RO; POST/PUT/PATCH/DELETE W → confirmación. Ver §1.1 (-Raw) y §1.4 (endpoints que dan 404).
coolify_skill/scripts/coolify.sh RO/W COOLIFY_TOKEN — Helper Bash legacy para sesiones Linux/WSL. En este repo se prefieren los wrappers PowerShell.

Referencia de la API: no cargues el árbol completo. Busca y abre un solo archivo:

rg -n "deploy|database|environment" .\coolify_skill\references
Get-Content .\coolify_skill\references\ops\deploy-by-tag-or-uuid.md

4. Deploy de proyectos nuevos a Coolify

⚠️ Lee esto antes de usar cualquier cosa de esta sección. El pipeline "una sola línea" fallaba porque /applications/* daba 404 (§1.4). Desde el 2026-08-29 sabemos que ese 404 es de Cloudflare, no de Coolify: apuntando COOLIFY_API_URL al origen (http://192.168.0.117:8000/api/v1) el namespace completo responde. Scripts marcados ❌ abajo deben funcionar así — pendiente de verificar en el próximo deploy; el flujo UI y la vía DB siguen como fallback.

Script R/W Env Estado en esta instancia
Publish-ProjectToCoolify.ps1 W GITHUB_TOKEN, COOLIFY_TOKEN ⚠️ Su paso 5 invoca New-CoolifyApplication.ps1 → probar contra el origen.
New-CoolifyApplication.ps1 W COOLIFY_TOKEN ⚠️ Usa POST /applications/public y PATCH /applications/{uuid} → funcionan vía origen (404 solo vía Cloudflare).
Invoke-CoolifyRollback.ps1 W COOLIFY_TOKEN ⚠️ Usa PATCH /applications/{uuid} → funciona vía origen.
New-CoolifyService.ps1 W COOLIFY_TOKEN ✅ Funciona. Usa POST /services. Es la vía válida para stacks multi-contenedor.
New-CoolifyAppViaDB.ps1 W (INSERT directo en la DB) — ⚠️ Último recurso. Escribe la fila en applications de la DB de Coolify saltándose API y UI. Sin validación ni rollback. Requiere -EnvironmentId y -GithubRepoId reales.
coolify-ui/coolify-login.mjs + Configure-CoolifyComposeApp.mjs W (vía navegador) COOLIFY_EMAIL, COOLIFY_PASSWORD ✅ Fallback soportado para apps git build-from-source. Credenciales probables ya en .env.local.ps1 (sin verificar).

Vías, en orden de preferencia:

  1. Stack multi-contenedor con docker-compose.coolify.yml → New-CoolifyService.ps1 (API).
  2. App git build-from-source → API contra el origen; si falla, flujo UI con Playwright (coolify-ui/).
  3. Último recurso → New-CoolifyAppViaDB.ps1.

Detalle completo del flujo v4.1.2 y sus trampas (BOM UTF-8 rompe el parser YAML de Coolify; "Reload Compose File" es obligatorio; fijar dominios por servicio o sale 503; no encolar deploys concurrentes) en deploy_skill/references/coolify-4.1.2-notes.md.

4.1 Scripts de deploy que funcionan sin depender de /applications

Script R/W Env Parámetros Qué hace
Initialize-CoolifyProject.ps1 W (solo local) — -Path -Stack {node|python|compose|static} -AppPort -Force Genera Dockerfile/compose/.dockerignore compatibles. Idempotente: no sobreescribe sin -Force.
Test-PreDeployChecklist.ps1 RO — -Path -ExpectedPort -Strict Valida el proyecto contra las reglas duras de AGENTS-coolify-apps.md. Gate obligatorio antes de cualquier push.
New-GitHubRepo.ps1 W (remoto) GITHUB_TOKEN -Name -Description -Private -Owner Crea el repo en GitHub. Idempotente: avisa si ya existe.
Invoke-GitHubApi.ps1 RO/W GITHUB_TOKEN -Method -Path -BodyJson -Raw API de GitHub. Default → objetos (§1.1).
Test-PostDeploy.ps1 RO COOLIFY_TOKEN (opcional) -Fqdn -ContainerName -SiblingService -ApplicationUuid Verifica el estado en Coolify: contenedores, logs del proxy, DNS entre hermanos. -ApplicationUuid consulta /applications/* → vía pública da 404 (Cloudflare), vía origen funciona.
Test-ServiceOnline.ps1 RO — -Fqdn -Path -ExpectedStatusCode -ExpectTitle -Screenshot -SkipBrowser -TimeoutMs -Retries La "definición de done". Dos capas: HTTP 200 vía curl + render real en Chromium (Playwright). Detecta 502 de Traefik, TLS a medias y crashes de JS del cliente. Sin Node/Playwright la capa de navegador se omite con warning, no falla.
deploy_skill/scripts/verify-online.mjs RO — (invocado por el script de arriba) Capa de navegador de Test-ServiceOnline.ps1: navegación real con Playwright, captura pageerror y requests fallidos del main frame. No lo invoques directo. Requiere npm install en la raíz del repo.

git push usa Windows Credential Manager (wincred), no el PAT. Verificado para la cuenta urieljarethbusiness-cpu.

Plantillas: deploy_skill/references/templates/ — Dockerfile.node, Dockerfile.python, docker-compose.app-db.yml, env.local.template.ps1.


5. Gitea — hosting git self-hosted

Distinto de deploy_skill: esto administra la capa de hosting git, no Coolify. El propio repo Manager vive aquí.

Script R/W Env Parámetros Qué hace
Test-GiteaConnection.ps1 RO GITEA_URL, GITEA_TOKEN — Smoke test: /version, /user, /settings/api, /repos/search. Sale 1 si algo falla.
Get-GiteaRepo.ps1 RO GITEA_URL, GITEA_TOKEN -Owner -Name -Search -List Lee, lista o busca repos. -Owner default = usuario del token.
Invoke-GiteaApi.ps1 RO/W GITEA_URL, GITEA_TOKEN -Method -Path -BodyJson -Raw API de Gitea. Usa curl.exe --data-binary con UTF-8 sin BOM (el parser de Gitea se rompe con BOM). Default → objetos (§1.1).
New-GiteaRepo.ps1 W GITEA_URL, GITEA_TOKEN -Name -Description -Private -Owner -NoAutoInit Crea repo (idempotente). -NoAutoInit evita el README del lado servidor para poder empujar historia local sin conflicto.
Sync-GiteaRemote.ps1 W GITEA_URL, GITEA_TOKEN -AppPath -Name -Owner -RemoteName -Branch -CreateIfMissing -Private -Force Cablea el remoto y hace push headless. El token nunca toca el disco: va en un http.extraHeader de un solo uso, no en .git/config. -RemoteName gitea (default) convive con un origin de GitHub.

6. Reglas de seguridad (no negociables)

  1. Read-only primero. El default es diagnosticar: list, status, logs, inspect, health checks.
  2. Confirmación explícita antes de cualquier cambio de estado. Aplica a: pct/qm start/stop/reboot/destroy; docker restart/stop/rm/compose up-down; deploys de Coolify y cualquier POST/PUT/PATCH/DELETE; escritura de variables de entorno; y todo cambio de firewall, red, storage, volumen, clave o token. Antes de una acción riesgosa: captura el estado actual y enuncia el camino de rollback.
  3. Nunca escribas secretos en el repo. Ni tokens, ni passwords, ni claves privadas, ni cookies, ni secretos de token PVE — no en Markdown, no en scripts, no en logs. Viven solo en .env.local.ps1 (gitignored) o en el almacén de secretos del SO. Al depurar bases de datos, verifica conectividad sin imprimir credenciales.
  4. Prefiere los scripts del repo antes que cadenas de comandos manuales largas, y no construyas comandos destructivos amplios a partir de strings generados.
  5. -Force existe en varios scripts para saltarse los prompts. Úsalo solo después de que el usuario haya aprobado el plan concreto.

7. Dónde está el resto del contexto

Qué necesitas Dónde
Arquitectura + router de intención CLAUDE.md
Topología verificada (fuente de verdad del estado) proxmox-inventory.md
Procedimientos concretos runbooks/
Casos resueltos paso a paso casos/
Incidentes archivados incidentes/
Contrato para construir una app deployable AGENTS-coolify-apps.md
Reglas operativas por dominio agent/SKILL.md, coolify_skill/SKILL.md, deploy_skill/SKILL.md, gitea_skill/SKILL.md
Guías de uso por dominio (ejemplos ejecutables) los TOOLS.md de cada carpeta *_skill/