From 5ce09b68aa631f6f466f4f0e9ce63124585f63b0 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:42:23 +0800 Subject: [PATCH 01/19] =?UTF-8?q?fix(docs):=20=E6=8A=8A=E8=B5=84=E6=BA=90?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E8=A1=A5=E6=88=90=E5=86=B3=E7=AD=96=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=20F,=E5=BC=BA=E8=B0=83=E5=85=88=E6=9F=A5=20UUID=20?= =?UTF-8?q?=E4=B8=8E=20--help=20(issue=20#2-01)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #01 的能力表与边界声明已在 16e372d 订正(README ✅、SKILL "Resource Creation"); 本提交补齐 issue 要求的"可走通路径"细节: - 在 SKILL.md 把 "Resource Creation" 升为决策树路径 F - 先 `server list` / `project list` / `project get` 拿 placement UUID,再 create - 标注 `app create public` 的最小必填 flag(git-repository/branch/build-pack/ports-exposes) - 保留保守提醒:create 类命令参数多且随版本变化,执行前 `--help` 核对 Co-Authored-By: Claude Opus 4.8 (1M context) --- SKILL.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/SKILL.md b/SKILL.md index 2b4128c..da11d18 100644 --- a/SKILL.md +++ b/SKILL.md @@ -108,13 +108,22 @@ Supported types: postgresql / mysql / mariadb / mongodb / redis / keydb / clickh **External access branch**: when a request involves "make the database externally accessible / reachable from another machine / reachable from Vercel", or "connect to the database via a domain" / "expose the database port", **first read `references/database-access.md`**, and confirm with the user following its recommended order (**internal > tunnel > hardened public exposure**); **don't go straight to `--is-public`**. Key points: a database speaks TCP, not HTTP (`https://db.example.com` won't connect); a client on the same machine as the database uses the internal network, an external machine that can keep a process running uses a tunnel, and **serverless platforms like Vercel go through the HTTP layer (a raw TCP tunnel won't work for them)**; if public exposure is truly required, first follow the standard `--is-public` procedure in `safety-rules.md` and warn that there is no TLS by default. -## Resource Creation +### F. Resource Creation (from scratch) -The CLI can create resources from scratch (this is no longer Web-UI-only): +The CLI can create resources from scratch (this is no longer Web-UI-only). **First gather the placement UUIDs**, then run the create command: -- **App**: `coolify app create --server-uuid --project-uuid

--environment-name ...` — binds a git repo (or Dockerfile/image), sets build pack and ports. See `references/cli-cheatsheet.md`. -- **One-click service**: `coolify service create ` (run `coolify service create --list-types` to list types like wordpress / ghost / n8n / supabase). +```bash +coolify server list --format=json # → --server-uuid +coolify project list --format=json # → --project-uuid +coolify project get # → the environment name/uuid under that project +``` + +- **App**: `coolify app create --server-uuid --project-uuid

--environment-name ...` — binds a git repo (or Dockerfile/image), sets build pack and ports. Required for `public`: `--git-repository`, `--git-branch`, `--build-pack`, `--ports-exposes` (plus the three placement flags above). See `references/cli-cheatsheet.md`. +- **One-click service**: `coolify service create --server-uuid --project-uuid

--environment-name ` (run `coolify service create --list-types` to list types like wordpress / ghost / n8n / supabase). - **Database**: `coolify database create ...` (path E above). +- **Project** (if none exists yet): `coolify project create --name `. + +> Create commands carry many flags and change across CLI versions — always run `coolify app create --help` (or the matching `--help`) to confirm the exact flags before executing. The Web UI is still handy for first-time visual setup, dashboards/metrics, and some advanced settings — but creation no longer requires it. From 101710a07ef2920906de10a9bf7e8fdcf7414faf Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:43:20 +0800 Subject: [PATCH 02/19] =?UTF-8?q?fix(scripts):=20deploy-and-watch=20?= =?UTF-8?q?=E6=9C=AB=E5=B0=BE=E7=8A=B6=E6=80=81=E6=94=B9=E7=94=A8=20app=20?= =?UTF-8?q?deployments=20list=20(issue=20#2-02)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #02:原脚本用 `deploy list` 再按字段过滤取本 app 的最新部署。但全局列表无可靠 的 app-UUID 列(`application_id` 是内部数字 id,非 app uuid),by-uuid 部署永远 匹配不到。改用 issue 推荐的 `coolify app deployments list `——该端点本 身就只返回该 app 的部署,无需任何字段过滤,jq 失败时回退到同一命令的 table 输出。 Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/deploy-and-watch.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/scripts/deploy-and-watch.sh b/scripts/deploy-and-watch.sh index ba398cb..01e6c89 100644 --- a/scripts/deploy-and-watch.sh +++ b/scripts/deploy-and-watch.sh @@ -61,16 +61,18 @@ echo "📜 Following deployment logs (Ctrl-C stops following; the deployment kee echo "────────────────────────────────────────" coolify $CTX_FLAG app deployments logs "$APP_UUID" -f -# After following ends, report the final status +# After following ends, report the final status. +# Use `app deployments list ` — it is already scoped to this app, so we +# don't have to filter the global `deploy list` by uuid. (The global list has no +# reliable app-UUID column: `application_id` is an internal numeric id, not the +# app uuid, so matching it against $APP_UUID never works for by-uuid deploys.) echo "────────────────────────────────────────" echo "🔎 Latest deployment status:" if command -v jq >/dev/null 2>&1; then - # Field names verified against coolify-cli v1.6.2 (internal/models/deployment.go): - # a deployment exposes application_id (the app UUID) / application_name / deployment_uuid / status / created_at. - # There is no application_uuid or resource_uuid, so we correlate on application_id (uuid) or application_name (by-name deploys). - coolify $CTX_FLAG deploy list --format=json 2>/dev/null \ - | jq -r --arg u "$APP_UUID" --arg n "$TARGET" '[.[] | select(.application_id==$u or .application_name==$n)] | sort_by(.created_at) | last | " Status: \(.status // "unknown") Deployment ID: \(.deployment_uuid // .id // "?")"' \ - 2>/dev/null || coolify $CTX_FLAG deploy list + coolify $CTX_FLAG app deployments list "$APP_UUID" --format=json 2>/dev/null \ + | jq -r 'sort_by(.created_at) | last + | " Status: \(.status // "unknown") Deployment ID: \(.deployment_uuid // .uuid // "?")"' \ + 2>/dev/null || coolify $CTX_FLAG app deployments list "$APP_UUID" else - coolify $CTX_FLAG deploy list + coolify $CTX_FLAG app deployments list "$APP_UUID" fi From 6c18af6b457212fcbd3977d468b0d8a14c005c41 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:45:08 +0800 Subject: [PATCH 03/19] =?UTF-8?q?feat(security):=20=E5=BC=95=E5=85=A5=20AP?= =?UTF-8?q?I=20token=20=E6=9C=80=E5=B0=8F=E6=9D=83=E9=99=90=E6=A8=A1?= =?UTF-8?q?=E5=9E=8B=20(issue=20#2-03)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #03:skill 面向"别人对着自己的生产 Coolify",token abilities 才是限制 Agent 跑飞破坏范围的根本控制,此前完全没提。补齐: - SKILL First-Time Setup:新增"Token permissions (least privilege)"表, 列出 read/deploy/write/read:sensitive/root 各 ability 含义与推荐组合 (日常 read+deploy;改配置才加 write;永不用 root) - safety-rules:新增 token 权限段——read:sensitive=服务端脱敏(非自觉)、 Allowed IPs、team scoping,以及"403 读返回体 missing permissions"定位法 - cheatsheet:403 troubleshooting 行升级为"--debug 读 403 body 的 missing permissions,补对应 ability,勿升级到 root" - README / README.zh-CN Requirements:API token 加最小权限说明 Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 +- README.zh-CN.md | 2 +- SKILL.md | 18 ++++++++++++++++++ references/cli-cheatsheet.md | 2 +- references/safety-rules.md | 10 ++++++++++ 5 files changed, 31 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 417c47b..384f820 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ The agent enables this skill automatically: look up the UUID → trigger the dep ## Requirements - A self-hosted **Coolify** instance (typically one VPS running a few Node / Next.js / Docker services). -- A Coolify **API token** (generate it in the Web UI under `/security/api-tokens`). +- A Coolify **API token** (generate it in the Web UI under `/security/api-tokens`). **Scope it least-privilege**: `read` + `deploy` for day-to-day ops, add `write` only to change config / create resources, and **never** hand an agent a `root` token. Details in [`references/safety-rules.md`](references/safety-rules.md). - The official **coolify CLI** ([coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli), the Go build — install it with the script below). - **Claude Code**, or any other agent that supports `SKILL.md` (e.g. Codex). diff --git a/README.zh-CN.md b/README.zh-CN.md index 9faadfe..a6d792f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -21,7 +21,7 @@ Agent 会自动启用本 skill:查 UUID → 触发部署 → 跟随日志 → ## 环境要求 - 一台自托管的 **Coolify** 实例(典型:一台 VPS + 已部署若干 Node / Next.js / Docker 服务)。 -- 一个 Coolify **API Token**(在 Web UI 的 `/security/api-tokens` 生成)。 +- 一个 Coolify **API Token**(在 Web UI 的 `/security/api-tokens` 生成)。**按最小权限授予**:日常运维用 `read` + `deploy`,改配置 / 创建资源才加 `write`,**绝不**给 Agent 用 `root` token。详见 [`references/safety-rules.md`](references/safety-rules.md)。 - 官方 **coolify CLI**([coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli),Go 版本,可用下方脚本一键安装)。 - **Claude Code**,或其它支持 `SKILL.md` 的 Agent(如 Codex)。 diff --git a/SKILL.md b/SKILL.md index da11d18..b4656e7 100644 --- a/SKILL.md +++ b/SKILL.md @@ -44,6 +44,24 @@ coolify context add -d coolify context verify ``` +### Token permissions (least privilege) + +The token's abilities are the real control over how much damage a runaway agent can do — set them when generating the token in the Web UI, not afterward. Coolify (Laravel Sanctum) abilities: + +| Ability | Grants | Recommendation | +|---|---|---| +| `read` | read all non-sensitive resources | baseline, always include | +| `deploy` | trigger deployments / restarts | include for day-to-day ops | +| `write` | create / update / delete config & resources | add **only** when you'll change config or create resources | +| `read:sensitive` | reveal passwords / secrets / full compose | add **only** if the agent genuinely needs secret values (see below) | +| `root` | bypass every permission check; can even toggle the API itself | **never** — do not issue a `root` token to an agent | + +- **Day-to-day ops** (deploy, logs, restart, status): `read` + `deploy`. +- **Changing config or creating resources** (`app/service/database create`, `update`, `env sync`): add `write`. +- **`read:sensitive` is server-side redaction, not an honor system.** Without it, the server itself redacts passwords / keys / compose, and `-s` / `--show-sensitive` returns nothing — that's a harder guarantee than "the agent promises not to print secrets". Only grant it when secret values are actually needed. +- **Allowed IPs**: in the Coolify API settings, restrict the token's source IPs to your known address(es). Leaving it blank / `0.0.0.0` means any host with the token can use it — not recommended for production. +- **Team scoping**: a token only sees resources in its own team. To manage another team, generate a separate token for it. + When it can't connect, work through the "Troubleshooting" section of `references/cli-cheatsheet.md` item by item. ## Operations Decision Tree diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 640272f..168ab7d 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -202,7 +202,7 @@ coolify resources list --format=json | jq -r '.[] | select(.status!="running") | |---|---|---| | `connection refused` / timeout | Wrong URL; VPS firewall not opened; Coolify not running | First test the web entry point with `curl -I `; check the VPS firewall ports | | `401 Unauthorized` | Token wrong or deleted | Regenerate the token in the Web UI, update with `coolify context set-token` | -| `403 Forbidden` | Insufficient token permissions | Check the permission scope of that token in Coolify | +| `403 Forbidden` | Token is missing a required ability (`read`/`deploy`/`write`/`read:sensitive`) | Re-run with `--debug` and read the 403 body — it lists the **missing permissions**. Add that ability to the token in the Web UI; never escalate to a `root` token. See `references/safety-rules.md` | | `certificate verify failed` | HTTPS certificate not configured properly | **Preferably** configure TLS in Coolify before connecting. ⚠️ Downgrading to `http://` sends the Bearer Token in plaintext over the wire; only for trusted internal networks/temporary troubleshooting, and the token should be rotated afterward | | Command can't find a resource | UUID expired/misremembered | Run ` list --format=json` again to get the UUID | | Unsure about a flag | CLI version differences | `coolify --help` to see the actual flags for the current version | diff --git a/references/safety-rules.md b/references/safety-rules.md index bf6c880..f61677b 100644 --- a/references/safety-rules.md +++ b/references/safety-rules.md @@ -62,6 +62,16 @@ Before executing any database **creation or modification** that includes `--is-p > The order of recommendation is always: **internal > tunnel > public hardening**. `--is-public` is the last option, and is never the default. For a full comparison of approaches, see `references/database-access.md`. +## Token permissions (least privilege) and the 403 signal + +The token's abilities cap how much an agent can do — this is the primary blast-radius control, more reliable than any "the agent will be careful" promise. Coolify (Laravel Sanctum) abilities: `read` / `deploy` / `write` / `read:sensitive` / `root`. + +- **Recommended scoping**: day-to-day ops = `read` + `deploy`; add `write` only to change config or create resources; **never** issue a `root` token (it bypasses every check and can toggle the API itself). See `SKILL.md` → First-Time Setup for the full table. +- **`read:sensitive` = server-side redaction.** When the token lacks it, the server redacts passwords / secrets / compose before they ever reach the wire, and `-s` / `--show-sensitive` comes back empty. This is a hard boundary, not an honor system — prefer withholding it unless secret values are genuinely needed. +- **Allowed IPs**: restrict the token's source IPs in the Coolify API settings; blank / `0.0.0.0` means anyone holding the token can use it. +- **Team scoping**: a token only sees its own team's resources; managing another team needs a separate token. +- **On `403 Forbidden`, read the response body.** Coolify's 403 lists the *missing* permissions. Run the failing command with `--debug` to see that body and identify exactly which ability the token lacks — then either add that ability in the Web UI or stop, rather than guessing. Do **not** "fix" a 403 by reaching for a `root` token. + ## Meta-rules for the Agent - **When unsure, ask.** For any operation where you cannot be certain whether it affects production, stop and ask the user instead of deciding for them. From 2f0084b56162883d647f93130a4e024097aab5a4 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:46:47 +0800 Subject: [PATCH 04/19] =?UTF-8?q?fix(docs):=20=E6=BE=84=E6=B8=85=20env=20s?= =?UTF-8?q?ync=20=E7=9A=84=20build-time/runtime=20=E8=AF=AD=E4=B9=89=20(is?= =?UTF-8?q?sue=20#2-04)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #04:`--build-time` 与 `--runtime` 注册默认值都是 true,但代码仅在显式传入时 才下发;`--help` 显示 default:true 会让人误以为"裸 sync 即全部 build-time", 也误以为"不加 --build-time 就能把密钥挡在 build 层外"——实则要排除 build 层 必须显式 `--build-time=false`。且 sync 是全文件一套 flag,敏感/非敏感须分两遍。 - deploy-patterns Next.js + env 分层:把"不加 --build-time"改为敏感那遍显式 `--build-time=false`,并写明 sync 全文件一套 flag - cheatsheet Env:补 `--runtime`(默认 true);加 --help default 与真实行为 不一致的显著警告;env create 同样有 build-time/runtime/is-multiline/comment - SKILL D 段:补 build-time 默认 true 的注意事项与 --build-time=false 排除法 Co-Authored-By: Claude Opus 4.8 (1M context) --- SKILL.md | 2 +- references/cli-cheatsheet.md | 9 +++++++-- references/deploy-patterns.md | 14 +++++++++----- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/SKILL.md b/SKILL.md index b4656e7..0927bc2 100644 --- a/SKILL.md +++ b/SKILL.md @@ -109,7 +109,7 @@ coolify app env sync --file .env.production # incremental sync ``` **Key semantics**: `env sync` is incremental — it overwrites existing variables and creates missing ones, **but does not delete variables that aren't in the file**. To mirror completely, first list and then delete each one (deletion is a destructive operation and requires confirmation). -For variables needed at build time, add `--build-time`; for preview environments, use `--preview`. For env layering conventions, see `references/deploy-patterns.md`. +For variables needed at build time, pass `--build-time=true`; for preview environments, use `--preview`. **Caveat**: `--build-time` (and `--runtime`) default to `true`, and `sync` applies one flag set to the whole file — so a bare sync of a `.env` containing secrets may carry them into the build layer. To keep secrets out, sync them in a separate pass with `--build-time=false`. For env layering conventions, see `references/deploy-patterns.md`. ### E. Databases and Backups diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 168ab7d..4e88eb2 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -113,11 +113,16 @@ coolify app env delete # Batch sync from .env (most common) coolify app env sync --file .env -coolify app env sync --file .env.production --build-time +coolify app env sync --file .env.public --build-time=true # frontend / build-time vars +coolify app env sync --file .env.secret --build-time=false # runtime-only, keep out of build layer ``` **sync behavior**: updates existing + creates missing, and **does not delete** variables not present in the file. -**flag meanings**: `--build-time` available at build time; `--preview` available for preview deployments; `--is-literal` no variable interpolation (use when the value contains `$`); `--is-multiline` multi-line values. +**sync flags**: `--build-time` (default **true**) available at build time; `--runtime` (default **true**) available at runtime; `--preview` available in preview deployments; `--is-literal` no variable interpolation (use when the value contains `$`); `-f`/`--file` is the **path** (required), not `--force`. + +> ⚠️ **`--help` default vs. real behavior**: the help shows `--build-time (default: true)` and `--runtime (default: true)`, but a value is only sent when you **explicitly** pass the flag — a bare `sync` leaves both to the server default. So don't assume "bare sync = everything build-time", and don't assume "omitting `--build-time` keeps secrets out of the build layer". When you need a specific behavior, set it explicitly (`--build-time=false` / `--build-time=true`). And `sync` applies **one flag set to the entire file**, so split sensitive vs. non-sensitive into separate files/passes. + +> `env create` carries the same `--build-time` / `--runtime` (both default true), plus `--is-multiline` and `--comment`. ## Database diff --git a/references/deploy-patterns.md b/references/deploy-patterns.md index 7456a94..e2de867 100644 --- a/references/deploy-patterns.md +++ b/references/deploy-patterns.md @@ -64,12 +64,16 @@ coolify app update \ ``` Key points: -- `NEXT_PUBLIC_*` variables are **injected at build time** and must be synced with `--build-time`, otherwise the frontend won't get them: +- **`env sync` applies one set of flags to the whole file** — it can't tag individual variables within a single sync. So split a mixed `.env` and sync in two passes. +- `NEXT_PUBLIC_*` variables are **injected at build time**; sync them with `--build-time=true`, otherwise the frontend won't get them: ```bash - coolify app env sync --file .env.production --build-time + coolify app env sync --file .env.public --build-time=true # frontend / build-time vars ``` -- Server-side runtime variables (database connection strings, API keys) can be synced normally and don't need `--build-time`. -- Note the distinction: if a single `.env` contains both `NEXT_PUBLIC_*` and server-side secrets, you may need to sync in two passes (one with `--build-time` for just the frontend variables, one without for the backend), or you can make everything build-time, but then the secrets end up in the build layer — weigh the security tradeoff. +- Server-side secrets (database connection strings, API keys) should be **kept out of the build layer**. ⚠️ But `--build-time` **defaults to `true`**, so a *bare* sync (no flag) does not reliably exclude them — you must pass `--build-time=false` explicitly: + ```bash + coolify app env sync --file .env.secret --build-time=false # runtime-only secrets + ``` +- In short: frontend file → `--build-time=true`; secret file → `--build-time=false`. **Do not rely on "omitting `--build-time`" to keep secrets out of the build layer** — see the warning in `references/cli-cheatsheet.md` (Env) about the `--help` default vs. real behavior. ## Docker / Docker Compose @@ -106,7 +110,7 @@ Recommended local → Coolify mapping: |---|---|---| | `.env.local` | Local development, **not committed, not synced** | don't sync | | `.env.production` | Production config (the part without secrets) | `coolify app env sync --file .env.production` | -| Secrets | Database strings/API keys, etc. | separate `env create`, or put them in a gitignored `.env.secrets` and sync separately | +| Secrets | Database strings/API keys, etc. | separate `env create`, or put them in a gitignored `.env.secrets` and sync separately **with `--build-time=false`** (keep them out of the build layer) | Red lines: - **Secrets never go into Git**. If `.env.production` contains secrets, add it to `.gitignore`; only commit non-sensitive config. From e7fe696dee21d91a9e0e7ddaa2d552f11206b8b4 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:48:53 +0800 Subject: [PATCH 05/19] =?UTF-8?q?feat(setup):=20=E6=96=B0=E5=A2=9E=20gen-r?= =?UTF-8?q?eference.sh=20=E7=94=A8=20coolify=20docs=20=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E7=B2=BE=E7=A1=AE=E5=8F=82=E8=80=83=20(issue?= =?UTF-8?q?=20#2-06)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #06:手维护的 cheatsheet 会持续 drift。CLI 自带 `coolify docs`(markdown/llms, llms 即"Generate llms.txt for AI agents")。新增 anti-drift 入口: - scripts/gen-reference.sh:跑 `coolify docs markdown` + `coolify docs llms`, 输出到 references/_generated/(含 VERSION.txt 标注版本);.gitignore 忽略之 - SKILL Core Principle #2:改为"flag 真实值以 --help 或生成参考为准;cheatsheet 仅高频速查 + jq + 故障表,可能 drift" - cheatsheet 顶部:注明生成参考为权威来源,本表仅速查 - SKILL Scripts 段 + 中英 README 项目结构:登记 gen-reference.sh Co-Authored-By: Claude Opus 4.8 (1M context) --- .gitignore | 3 +++ README.md | 3 ++- README.zh-CN.md | 3 ++- SKILL.md | 4 +++- references/cli-cheatsheet.md | 2 +- scripts/gen-reference.sh | 37 ++++++++++++++++++++++++++++++++++++ 6 files changed, 48 insertions(+), 4 deletions(-) create mode 100755 scripts/gen-reference.sh diff --git a/.gitignore b/.gitignore index 3133667..e04cad2 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,6 @@ .vscode/ .idea/ *.swp + +# Generated CLI reference (per-version, produced by scripts/gen-reference.sh) +references/_generated/ diff --git a/README.md b/README.md index 384f820..7be586f 100644 --- a/README.md +++ b/README.md @@ -135,7 +135,8 @@ coolify-ops/ └── scripts/ ├── install-cli.sh # Cross-platform installer for the official CLI ├── health-check.sh # One-shot health check (CLI / context / resource status) - └── deploy-and-watch.sh # Deploy + follow logs until success / failure + ├── deploy-and-watch.sh # Deploy + follow logs until success / failure + └── gen-reference.sh # Dump this CLI version's full reference → references/_generated/ ``` ## License diff --git a/README.zh-CN.md b/README.zh-CN.md index a6d792f..c3d057d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -131,7 +131,8 @@ coolify-ops/ └── scripts/ ├── install-cli.sh # 跨平台安装官方 CLI ├── health-check.sh # 一键体检(CLI / context / 资源状态) - └── deploy-and-watch.sh # 部署 + 自动跟日志直到 success / fail + ├── deploy-and-watch.sh # 部署 + 自动跟日志直到 success / fail + └── gen-reference.sh # 生成当前 CLI 版本的完整参考 → references/_generated/ ``` ## License diff --git a/SKILL.md b/SKILL.md index 0927bc2..bb37287 100644 --- a/SKILL.md +++ b/SKILL.md @@ -11,12 +11,13 @@ Remotely operate a Coolify instance through the official `coolify` CLI (the Go v 1. **The CLI is an HTTP API client, not SSH.** Every operation goes through the Coolify REST API using a Bearer Token, and has nothing to do with the server's SSH credentials. If a command can't connect, suspect API reachability and the Token first, not SSH. -2. **The CLI is self-documenting — prefer `--help` over memory.** The CLI keeps evolving and flags change. When unsure about a subcommand or argument, run `coolify --help` before acting; don't guess flags from memory. Common levels: +2. **The CLI is self-documenting — `--help` (or a generated reference) is the source of truth for flags.** The CLI keeps evolving and flags change. The authoritative flag values are whatever `coolify --help` prints, or a version-exact reference generated by `scripts/gen-reference.sh` (which runs `coolify docs markdown` / `coolify docs llms` into `references/_generated/`). The hand-maintained `references/cli-cheatsheet.md` is only a high-frequency quick reference (+ jq recipes + troubleshooting table) and can drift — never guess flags from memory. Common levels: ```bash coolify --help coolify app --help coolify app deployments --help coolify database --help + bash scripts/gen-reference.sh # one-shot: dump this CLI version's full reference ``` 3. **JSON for yourself, table for people.** When you need to parse the output (grab a UUID, judge state), always add `--format=json` and extract with `jq`. When showing state directly to the user, use the default table. @@ -157,3 +158,4 @@ The Web UI is still handy for first-time visual setup, dashboards/metrics, and s - `scripts/install-cli.sh` — cross-platform install of the official CLI (macOS/Linux, auto-detects architecture). - `scripts/health-check.sh` — one-shot health check: whether the CLI is present, whether the context connects, and the state of each resource. Run it first when troubleshooting "how's everything doing overall". - `scripts/deploy-and-watch.sh ` — triggers a deploy and automatically follows the logs, only returning once the deploy is success or failed. The default recommended way to deploy. +- `scripts/gen-reference.sh` — dumps this CLI version's full command reference (via `coolify docs markdown` / `coolify docs llms`) into `references/_generated/`. Run it once after install/upgrade; treat the output as the authoritative flag source. diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 4e88eb2..084a8ef 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -1,6 +1,6 @@ # Coolify CLI Command Quick Reference -> This is a command reference for the `coolify` CLI (coollabsio/coolify-cli, the Go version). The CLI is continuously evolving, so **flags should be taken from the actual output of `coolify --help`**. This table is a quick reference for commonly used items. +> This is a command reference for the `coolify` CLI (coollabsio/coolify-cli, the Go version). The CLI is continuously evolving, so **flags should be taken from the actual output of `coolify --help`** — or, for a version-exact dump, from `references/_generated/` (run `bash scripts/gen-reference.sh`, which calls `coolify docs markdown` / `coolify docs llms`). **That generated reference is authoritative; this table is only a high-frequency quick reference** for commonly used items, jq recipes, and troubleshooting. ## Table of Contents diff --git a/scripts/gen-reference.sh b/scripts/gen-reference.sh new file mode 100755 index 0000000..176730c --- /dev/null +++ b/scripts/gen-reference.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash +# gen-reference.sh — generate a version-exact command reference straight from the +# installed coolify CLI, so the agent can rely on it instead of the hand-maintained +# cheatsheet (which drifts across CLI versions). Output lands in references/_generated/ +# (gitignored). Re-run after `coolify update`. +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +SKILL_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +OUT_DIR="$SKILL_DIR/references/_generated" + +command -v coolify >/dev/null 2>&1 || { echo "❌ coolify CLI not found. Run install-cli.sh first."; exit 1; } + +VER="$(coolify version 2>/dev/null | head -n1 || echo unknown)" +echo "📚 Generating reference from coolify CLI v${VER} → references/_generated/" +mkdir -p "$OUT_DIR" + +# Markdown docs (one file per command tree) — human + agent readable +if coolify docs markdown -o "$OUT_DIR/markdown" >/dev/null 2>&1; then + echo " ✅ markdown → references/_generated/markdown/" +else + echo " ⚠️ 'coolify docs markdown' unavailable (older CLI?) — skipped" +fi + +# llms.txt / llms-full.txt — purpose-built for AI agents ("Generate llms.txt for AI agents") +if coolify docs llms -o "$OUT_DIR/llms.txt" --full-output "$OUT_DIR/llms-full.txt" >/dev/null 2>&1; then + echo " ✅ llms.txt → references/_generated/llms.txt (+ llms-full.txt)" +else + echo " ⚠️ 'coolify docs llms' unavailable (older CLI?) — skipped" +fi + +# Stamp the version so the agent knows exactly what these files match +printf 'coolify CLI version: %s\ngenerated by: scripts/gen-reference.sh\n' "$VER" > "$OUT_DIR/VERSION.txt" + +echo "" +echo "Done. Treat references/_generated/ as the authoritative flag source for THIS CLI version;" +echo "the hand-written references/cli-cheatsheet.md is only a high-frequency quick reference." From 50d10462997d6bdd181ce2418349f4e5581cfc83 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:52:17 +0800 Subject: [PATCH 06/19] =?UTF-8?q?docs(cheatsheet):=20=E8=A1=A5=E9=BD=90?= =?UTF-8?q?=E7=BC=BA=E5=A4=B1=E7=9A=84=E5=91=BD=E4=BB=A4=E7=BB=84=20(issue?= =?UTF-8?q?=20#2-07)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #07:以下命令组此前完全缺失,均按 v1.6.2 --help 核实补入: - GitHub App 集成(list/get/repos/branches/create/update/delete)—— app create github 依赖其 app-uuid;create 所需 8 个必填 flag 已列出 - Private keys(list/add/remove)——命令名是 `private-key`(非 privatekeys) - Storage 持久卷(app/database/service storage 同形,create --type persistent|file) - App previews delete(预览部署清理) - Server add / remove(原只有 list/get/validate/domains) - Database 也有 env 与 storage:Env 段说明从"仅 app/service"改为含 database; Database 段补 env/storage 指引 - Teams(list/current/get/members)——与 token team scoping 相关 - 目录补上述小节锚点 Co-Authored-By: Claude Opus 4.8 (1M context) --- references/cli-cheatsheet.md | 67 +++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 084a8ef..b0bc483 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -12,6 +12,10 @@ - [Database](#database) - [Service](#service) - [Server](#server) +- [GitHub App integrations](#github-app-integrations) +- [Private keys](#private-keys) +- [Storage (persistent volumes)](#storage-persistent-volumes) +- [Teams](#teams) - [Output formats & global flags](#output-formats--global-flags) - [Troubleshooting table](#troubleshooting-table) @@ -48,6 +52,7 @@ coolify app get # details coolify app start|stop|restart # lifecycle coolify app delete # delete (dangerous, requires confirmation; do not proactively add -f) coolify app logs # runtime logs (container stdout) +coolify app previews delete # clean up a PR preview deployment # Create a new app from a git repo / Dockerfile / image (pick the source subcommand) coolify app create public --server-uuid --project-uuid

--environment-name \ @@ -102,7 +107,7 @@ coolify deploy cancel # cancel an in-progress deployment ## Env -> The env subcommands for app and service are identical; the example below uses app. +> The env subcommands are identical across **app, service, and database** (e.g. `coolify database env list `, `coolify database env sync --file .env`); the examples below use app. ```bash coolify app env list @@ -148,6 +153,11 @@ coolify database backup create \ [--retention-days-locally 7] [--retention-amount-locally 5] coolify database backup trigger # back up immediately coolify database backup executions # backup execution records + +# databases also have env and storage subcommands (same shape as app): +coolify database env list +coolify database env sync --file .env # see Env section for flag caveats +coolify database storage list # see Storage section ``` > Backup flags verified against coolify-cli v1.6.2. Local retention uses the **`-locally`** suffix (`--retention-days-locally` / `--retention-amount-locally`) — there is **no** `--retention-*-local`. S3 has the matching `--retention-days-s3` / `--retention-amount-s3`, plus `--retention-max-storage-locally` / `--retention-max-storage-s3`, `--databases-to-backup`, `--disable-local-backup`, `--dump-all`, and `--timeout`. @@ -174,6 +184,61 @@ coolify server get # details coolify server get --resources # including the resources on that server and their status coolify server validate # validate connection coolify server domains # domains on that server +coolify server add [-p 22] [-u root] [--validate] # register a new server +coolify server remove # remove a server (dangerous, requires confirmation) +``` + +## GitHub App integrations + +For deploying **private** GitHub repos; `app create github` needs the resulting App UUID (`--github-app-uuid`). Aliases: `gh`, `github-app`, `github-apps`. + +```bash +coolify github list # list GitHub App integrations +coolify github get # details +coolify github repos # repos the App can access +coolify github branches # branches of a repo +coolify github create --name --api-url https://api.github.com --html-url https://github.com \ + --app-id --installation-id --client-id --client-secret \ + --private-key-uuid # register a GitHub App (all listed flags required) +coolify github update ... # update integration +coolify github delete # delete integration (dangerous) +``` + +## Private keys + +SSH private keys for server auth and `app create deploy-key` private-repo deploys. Aliases: `private-keys`, `key`, `keys`. + +```bash +coolify private-key list # list keys +coolify private-key add # add a key (inline value or a file path) +coolify private-key remove # remove a key (dangerous) +``` + +## Storage (persistent volumes) + +Persistent volumes / file mounts for stateful resources — same shape for `app` / `database` / `service` (alias: `storages`). + +```bash +coolify app storage list +coolify app storage create --type persistent --name --mount-path /data +coolify app storage create --type file --mount-path /etc/app/config.yml --content "$(cat config.yml)" +coolify app storage update ... +coolify app storage delete # dangerous: may delete persisted data + +# database / service are identical — just swap the noun: +coolify database storage list +coolify service storage list +``` + +## Teams + +Tokens are **team-scoped** (see `references/safety-rules.md`); these show which team you're acting as. Alias: `team`. + +```bash +coolify teams list # all teams visible to the token +coolify teams current # the currently authenticated team +coolify teams get # team details +coolify teams members list # members of the current team ``` ## Output formats & global flags From 187e3a5fb986bc60b4d11d99756fdd2a3493b412 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:53:20 +0800 Subject: [PATCH 07/19] =?UTF-8?q?fix(docs):=20=E8=BD=AF=E5=8C=96=20"never?= =?UTF-8?q?=20SSH"=20=E7=BB=9D=E5=AF=B9=E5=8C=96=E8=A1=A8=E8=BF=B0,?= =?UTF-8?q?=E5=B9=B6=E6=8C=89=20v1.6.2=20=E5=AE=9E=E6=83=85=E6=A0=87?= =?UTF-8?q?=E6=B3=A8=20(issue=20#2-08)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #08:把"The CLI is an HTTP API client, not SSH"的绝对化措辞,改为"本 skill 范围内 (deploy/app/service/database/env/logs/backup 全部 v1.6.2 命令)走 REST API,与 SSH 无关"。 实测说明:issue 提到的 `init` / `firewall` / `common sshmesh` 在已验证的 v1.6.2 二进制 中**并不存在**(`coolify --help` 无这些命令),故不为其编造稳定文档;仅作为"未来 Coolify v5 的实验命令、走 SSH+root、不在本 skill 范围"的 caveat 提及,并明确:加固 公网 DB 端口的源 IP 限制仍用 ufw / 云安全组,与(未来的)CLI firewall(管 mesh 容器 规则)不是一回事。README 中英版同步去掉"与 SSH 无关"的绝对措辞。 Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 +- README.zh-CN.md | 2 +- SKILL.md | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7be586f..a8a3f75 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ > A **Claude Code / Codex agent skill** — drive the official [`coolify` CLI](https://github.com/coollabsio/coolify-cli) with natural language to remotely deploy, operate, and troubleshoot apps / services / databases on a self-hosted [Coolify](https://coolify.io) instance. -**It runs entirely on top of the official CLI.** This skill never touches your server directly — it translates your natural-language intent into [coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli) commands, and the CLI talks to Coolify's REST API over a Bearer token (nothing to do with SSH). Because the CLI keeps evolving, the skill has the agent run `coolify --help` to check flags rather than hard-coding them, avoiding version drift. +**It runs entirely on top of the official CLI.** This skill never touches your server directly — it translates your natural-language intent into [coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli) commands, and the CLI talks to Coolify's REST API over a Bearer token (not your server's SSH login). Because the CLI keeps evolving, the skill has the agent run `coolify --help` to check flags rather than hard-coding them, avoiding version drift. Once installed, just talk to the agent in plain language, e.g.: diff --git a/README.zh-CN.md b/README.zh-CN.md index c3d057d..0d243a1 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -8,7 +8,7 @@ > 一个 **Claude Code / Codex Agent Skill**——用自然语言驱动官方 [`coolify` CLI](https://github.com/coollabsio/coolify-cli),远程完成自托管 [Coolify](https://coolify.io) 实例上应用 / 服务 / 数据库的**部署、运维与排障**。 -**底层全靠官方 CLI 干活**:本 skill 自己不碰你的服务器,而是把你的自然语言意图翻译成 [coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli) 命令来执行;CLI 再通过 Bearer Token 调 Coolify 的 REST API 完成操作(与 SSH 无关)。CLI 在持续演进,skill 鼓励 Agent 用 `coolify --help` 自查 flag,避免版本漂移。 +**底层全靠官方 CLI 干活**:本 skill 自己不碰你的服务器,而是把你的自然语言意图翻译成 [coollabsio/coolify-cli](https://github.com/coollabsio/coolify-cli) 命令来执行;CLI 再通过 Bearer Token 调 Coolify 的 REST API 完成操作(用的是 REST API,不是服务器的 SSH 登录)。CLI 在持续演进,skill 鼓励 Agent 用 `coolify --help` 自查 flag,避免版本漂移。 装好后,直接对 Agent 说人话即可,例如: diff --git a/SKILL.md b/SKILL.md index bb37287..0aefc8c 100644 --- a/SKILL.md +++ b/SKILL.md @@ -9,7 +9,8 @@ Remotely operate a Coolify instance through the official `coolify` CLI (the Go v ## Core Principles -1. **The CLI is an HTTP API client, not SSH.** Every operation goes through the Coolify REST API using a Bearer Token, and has nothing to do with the server's SSH credentials. If a command can't connect, suspect API reachability and the Token first, not SSH. +1. **For everything in this skill's scope, the CLI is an HTTP API client — not SSH.** All the operations covered here (deploy / app / service / database / env / logs / backup — the entire v1.6.2 command surface) go through the Coolify REST API with a Bearer token; they have nothing to do with the server's SSH credentials. If a command can't connect, suspect API reachability and the token first, not SSH. + - *Caveat (out of scope):* some experimental, not-yet-GA commands in newer dev builds (WireGuard mesh / firewall bootstrapping for the upcoming Coolify v5) do run over SSH + root — but they are **not present in v1.6.2** and are not part of this skill. So don't over-generalize "the CLI never uses SSH" on a future build; and don't confuse such a future `firewall` command (which manages mesh container rules) with hardening a public database port — restricting a DB port's source IPs is still done with `ufw` / your cloud security group (see `references/database-access.md` §2.3). 2. **The CLI is self-documenting — `--help` (or a generated reference) is the source of truth for flags.** The CLI keeps evolving and flags change. The authoritative flag values are whatever `coolify --help` prints, or a version-exact reference generated by `scripts/gen-reference.sh` (which runs `coolify docs markdown` / `coolify docs llms` into `references/_generated/`). The hand-maintained `references/cli-cheatsheet.md` is only a high-frequency quick reference (+ jq recipes + troubleshooting table) and can drift — never guess flags from memory. Common levels: ```bash From 24dce537f933df97dc7e4b6ce480fe7312a71916 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:54:19 +0800 Subject: [PATCH 08/19] =?UTF-8?q?fix(security):=20=E6=BE=84=E6=B8=85=20tok?= =?UTF-8?q?en=20=E8=90=BD=E7=9B=98=E4=BD=8D=E7=BD=AE=E4=B8=8E=E8=BD=AE?= =?UTF-8?q?=E6=8D=A2,=E7=BA=A0=E6=AD=A3"=E7=BB=9D=E4=B8=8D=E5=86=99?= =?UTF-8?q?=E6=96=87=E4=BB=B6"=20(issue=20#2-09)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #09:safety-rules 原写"不把 token 写进任何文件",与 CLI 自身行为矛盾——CLI 合法地 把 token 持久化在 `~/.config/coolify/config.json`(文件 0600 / 目录 0750)。改为: - 这是 CLI 的合法存储,不需要"修正"或搬移;但 Agent 不应 cat / 回显 / 复制该文件 - 补轮换命令 `coolify context set-token `;并提示该文件有本地读取 风险,主机疑似被入侵时应在 Web UI 吊销并立即轮换 - 中英 README 的"不写进文件"同步改为"不从 CLI 自身配置文件里复制出来" Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 2 +- README.zh-CN.md | 2 +- references/safety-rules.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a8a3f75..0bf1275 100644 --- a/README.md +++ b/README.md @@ -119,7 +119,7 @@ Once configured, you don't need to memorize commands — describe what you want - **Destructive actions are confirmed.** Deleting a database/app, stopping production, force-deploying, and the like — the agent restates the impact and waits for your confirmation, and **never adds `-f` to skip confirmation on its own**. See [`references/safety-rules.md`](references/safety-rules.md). - **Don't expose databases to the public carelessly.** When a database needs external access, the order of preference is **internal > tunnel > hardened public**, and `--is-public` is off by default. To connect over a domain, turn off Cloudflare's orange cloud, and note that Coolify databases ship **without TLS** by default (a plaintext public connection leaks credentials). Full guide: [`references/database-access.md`](references/database-access.md). -- **Credentials stay private.** The agent won't print tokens in its replies or write them to files; passwords / connection strings surfaced by `--show-sensitive` are redacted as needed. +- **Credentials stay private.** The agent won't print tokens in its replies or copy them out of the CLI's own config store (`~/.config/coolify/config.json`, mode `0600`, where the CLI legitimately keeps them); passwords / connection strings surfaced by `--show-sensitive` are redacted as needed. - **Trust `--help` over the cheatsheet.** The CLI evolves; if a flag or JSON field ever looks off, confirm with `coolify --help` before relying on it. ## Project layout diff --git a/README.zh-CN.md b/README.zh-CN.md index 0d243a1..bfa371f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -115,7 +115,7 @@ coolify context verify - **危险操作要确认**:删库 / 删应用 / 停生产 / 强制部署等,Agent 会先复述影响并等你确认,**绝不主动加 `-f` 跳过确认**。详见 [`references/safety-rules.md`](references/safety-rules.md)。 - **数据库别随手怼公网**:让数据库被外部访问时,推荐度是 **内网 > 隧道 > 公网加固**,默认不开 `--is-public`。用域名连库要关掉 Cloudflare 橙云,且 Coolify 默认数据库**不开 TLS**(公网明文连接会暴露凭据)。完整说明见 [`references/database-access.md`](references/database-access.md)。 -- **凭据不外泄**:Agent 不在回复里明文打印 token、不写进文件;`--show-sensitive` 带出的密码 / 连接串按需脱敏。 +- **凭据不外泄**:Agent 不在回复里明文打印 token,也不把它从 CLI 自身的配置文件(`~/.config/coolify/config.json`,权限 `0600`,CLI 在此合法存储)里复制出来;`--show-sensitive` 带出的密码 / 连接串按需脱敏。 - **flag 以 `--help` 为准**:CLI 在演进,若某个 flag 或 JSON 字段看起来不对,先 `coolify --help` 核对再依赖。 ## 项目结构 diff --git a/references/safety-rules.md b/references/safety-rules.md index f61677b..716ceda 100644 --- a/references/safety-rules.md +++ b/references/safety-rules.md @@ -76,5 +76,5 @@ The token's abilities cap how much an agent can do — this is the primary blast - **When unsure, ask.** For any operation where you cannot be certain whether it affects production, stop and ask the user instead of deciding for them. - **Confirm batch operations one by one.** When running `deploy batch` or looping over multiple resources, first list the complete inventory for the user to review. -- **Don't remember tokens for the user, and don't leak secrets.** Don't print tokens in plaintext in replies; don't write tokens into any file. The output of `-s` / `--show-sensitive` (database passwords, connection strings, internal addresses) is given only when the user currently needs it — **don't proactively echo it, don't write it to files, and don't copy it anywhere outside the chat**; mask passwords in connection strings with `***` before displaying them whenever possible. +- **Don't leak secrets, and don't touch the token store.** Never print a token in plaintext in replies. The CLI **legitimately persists the token** at `~/.config/coolify/config.json` (file mode `0600`, directory `0750`) — that is its proper store, not something to "fix" or relocate. But the agent must never `cat` that file, echo its contents, or copy it elsewhere. To rotate a token use `coolify context set-token ` (generate the replacement in the Web UI first); if the host may be compromised, revoke the token in the Web UI and rotate immediately, since anything with local read access to that file can use it. The output of `-s` / `--show-sensitive` (database passwords, connection strings, internal addresses) is shown only when the user currently needs it — **don't proactively echo it, don't write it to files, and don't copy it anywhere outside the chat**; mask passwords in connection strings with `***` before displaying whenever possible. - **Don't silence errors.** When a command fails, give the real error to the user; don't paper over it as if "everything looks fine". From 8b99f50687cabbd78e9f8cf742e6dfdff0e4419a Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:56:49 +0800 Subject: [PATCH 09/19] =?UTF-8?q?fix(docs):=20=E6=BE=84=E6=B8=85=20-f=20?= =?UTF-8?q?=E5=9C=A8=E4=B8=8D=E5=90=8C=E5=91=BD=E4=BB=A4=E4=B8=8B=E7=9A=84?= =?UTF-8?q?=E5=90=AB=E4=B9=89,=E7=BA=A0=E6=AD=A3"=E7=BB=9D=E4=B8=8D?= =?UTF-8?q?=E5=8A=A0=20-f"=20(issue=20#2-10)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10:`env sync` 的 `-f` 是 `--file`(StringP("file","f",...)),与跳过确认无关, 原"绝不加 -f"会让 Agent 连 `-f .env` 都回避。实测进一步发现: - v1.6.2 **没有全局 `--force`**;`--force` 是按命令注册的 - `app delete`:`-f`/`--force` = 跳过删除确认 - `deploy name|uuid`:只有 `--force`(强制重部署),**无 `-f` 短选项** - `env sync`:`-f` = `--file`(.env 路径,必填,安全) - `database delete`:无 force flag(改用 --delete-volumes 等,默认 true) 改动:safety-rules 入口与 deploy 行、SKILL 原则 #4 改为"绝不主动加跳过确认的 --force,但 env sync 的 -f 是 --file";cheatsheet 全局 flag 段移除误标的 `-f, --force`,补 per-command 的 `-f` 含义清单;修正 `deploy name -f` → `--force`。 Co-Authored-By: Claude Opus 4.8 (1M context) --- SKILL.md | 2 +- references/cli-cheatsheet.md | 9 +++++++-- references/safety-rules.md | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/SKILL.md b/SKILL.md index 0aefc8c..89f7589 100644 --- a/SKILL.md +++ b/SKILL.md @@ -23,7 +23,7 @@ Remotely operate a Coolify instance through the official `coolify` CLI (the Go v 3. **JSON for yourself, table for people.** When you need to parse the output (grab a UUID, judge state), always add `--format=json` and extract with `jq`. When showing state directly to the user, use the default table. -4. **Confirm destructive operations first.** For irreversible operations or anything that affects production — `delete`, `stop` (production), forced deploys — you must restate to the user what you're about to do and wait for confirmation before executing. See `references/safety-rules.md`. **Never add `-f` to skip confirmation on your own initiative.** +4. **Confirm destructive operations first.** For irreversible operations or anything that affects production — `delete`, `stop` (production), forced deploys — you must restate to the user what you're about to do and wait for confirmation before executing. See `references/safety-rules.md`. **Never add a confirmation-skipping flag on your own initiative** — `--force`/`-f` on `app delete`, or `--force` on `deploy`. (Note: `env sync`'s `-f` is `--file`, the `.env` path — safe and required, not `--force`.) 5. **Always look up UUIDs, never guess them.** Before any operation targeting a specific resource, run `coolify list --format=json` to get the real UUID. Never fabricate or reuse a UUID from memory. diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index b0bc483..f1fd4eb 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -97,7 +97,7 @@ coolify app deployments logs # a specific deploymen coolify deploy name # deploy by name (recommended, easy to remember) coolify deploy uuid # deploy by UUID coolify deploy batch ,, # batch deploy multiple -coolify deploy name -f # force deploy (deploy even with no changes; use with caution) +coolify deploy name --force # force deploy (deploy even with no changes; --force only, no -f short) coolify deploy list # all deployment records coolify deploy get # single deployment details coolify deploy cancel # cancel an in-progress deployment @@ -253,9 +253,14 @@ coolify teams members list # members of the current team --token # temporarily override the token (CI scenarios) -s, --show-sensitive # show sensitive info (token/IP) --debug # print the full HTTP request/response (troubleshooting lifesaver) --f, --force # skip confirmation (only use after the user has explicitly agreed) ``` +> **`-f` is overloaded and per-command — there is no global `--force`/`-f` in v1.6.2:** +> - `coolify app delete -f` / `--force` → **skips the delete confirmation prompt** (never add on your own initiative). +> - `coolify deploy name|uuid --force` → **force a redeploy** (note: `--force` only, **no `-f` short form** here). +> - `coolify {app,service,database} env sync -f ` → here `-f` is `--file`, the `.env` **path** (required) — completely safe, use it freely. +> - `coolify database delete` has **no** force flag (instead: `--delete-volumes` / `--delete-configurations` / … , all default `true` — see `references/safety-rules.md`). + Common jq recipes: ```bash diff --git a/references/safety-rules.md b/references/safety-rules.md index 716ceda..fcb91c2 100644 --- a/references/safety-rules.md +++ b/references/safety-rules.md @@ -1,6 +1,6 @@ # Destructive-operation red lines -This skill operates on **real resources in production environments**. The following operations are irreversible or affect live services. **Before executing, you must restate to the user what is about to happen and wait for explicit confirmation.** **Never proactively add `-f`/`--force` to skip confirmation.** +This skill operates on **real resources in production environments**. The following operations are irreversible or affect live services. **Before executing, you must restate to the user what is about to happen and wait for explicit confirmation.** **Never proactively add a confirmation-skipping flag** — `--force` (or its `-f` short) on `app delete`, or `--force` on `deploy`. ⚠️ Note `-f` is overloaded: on `{app,service,database} env sync` it means `--file` (the `.env` path, required) and is completely safe — don't avoid *that* one. There is no global `--force` in v1.6.2; see the per-command breakdown in `references/cli-cheatsheet.md` (Output formats & global flags). ## Severity tiers @@ -20,7 +20,7 @@ This skill operates on **real resources in production environments**. The follow | Operation | Consequence | |---|---| | `coolify app stop` / `service stop` / `database stop` (production) | The live service goes offline, visible to users | -| `coolify deploy ... -f` (force deploy) | May overwrite a working version; first confirm that forcing is genuinely needed | +| `coolify deploy name\|uuid ... --force` (force deploy) | May overwrite a working version; first confirm that forcing is genuinely needed (`--force` only — no `-f` short) | | `coolify app restart` (production peak hours) | Brief interruption; safer during off-peak hours | | `coolify database backup delete` | Deletes a backup, reducing recoverability | | `coolify database create/update ... --is-public` (public database port) | Exposes the database TCP port to the public internet, visible to internet-wide scanners; Coolify databases **do not enable TLS** by default, so plaintext credentials/data are at risk of leaking. **Never default to this**; first follow the standard procedure below | From 0013cc8998881bdef872e1bdcd856d8a8b67d3ff Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:58:05 +0800 Subject: [PATCH 10/19] =?UTF-8?q?feat(scripts):=20install-cli.sh=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20brew=20/=20go=20install=20=E5=9B=9E?= =?UTF-8?q?=E9=80=80=20(issue=20#2-11)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #11:原脚本仅 `curl install.sh | bash` 一条路径,网络受限时无兜底。 - 安装顺序改为官方 curl 脚本 → Homebrew → `go install`,逐级回退;依赖 pipefail 确保 curl 失败不会被下游 bash 吞掉 - 全部失败时给出三条手动路径(brew / go / releases) - 顺手修正 `coolify --version`(实测会报 unknown flag)→ `coolify version` - go install 场景在 PATH 提示里补充 $(go env GOPATH)/bin README 兼容性版本号此前已填入实测 v1.6.2 / v4.1.1,无占位需处理。 Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/install-cli.sh | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) mode change 100644 => 100755 scripts/install-cli.sh diff --git a/scripts/install-cli.sh b/scripts/install-cli.sh old mode 100644 new mode 100755 index f259724..34bacca --- a/scripts/install-cli.sh +++ b/scripts/install-cli.sh @@ -1,21 +1,49 @@ #!/usr/bin/env bash # install-cli.sh — install the official Coolify CLI (coollabsio/coolify-cli) # Supports macOS / Linux with auto-detection; idempotent, skips if already installed. +# Install order: official curl script → Homebrew → `go install` (whichever is available). set -euo pipefail if command -v coolify >/dev/null 2>&1; then - echo "✅ coolify CLI already installed: $(coolify --version 2>/dev/null || echo 'version unknown')" + echo "✅ coolify CLI already installed: $(coolify version 2>/dev/null || echo 'version unknown')" echo " To upgrade: coolify update" exit 0 fi echo "📦 coolify CLI not detected, starting installation..." +# Each method returns non-zero (without aborting the script) if its tool is missing or it fails, +# so the `||` chain below can fall through to the next option. +try_official() { + command -v curl >/dev/null 2>&1 || return 1 + echo "→ Trying official install script (curl)…" + # pipefail (set above) makes the pipe fail if curl itself fails, so a 4xx/5xx won't be masked. + curl -fsSL https://raw.githubusercontent.com/coollabsio/coolify-cli/main/scripts/install.sh | bash +} + +try_brew() { + command -v brew >/dev/null 2>&1 || return 1 + echo "→ Trying Homebrew…" + brew install coollabsio/coolify-cli/coolify-cli +} + +try_go() { + command -v go >/dev/null 2>&1 || return 1 + echo "→ Trying 'go install'…" + go install github.com/coollabsio/coolify-cli/coolify@latest +} + OS="$(uname -s)" case "$OS" in Darwin|Linux) - # Official install script (installs to /usr/local/bin/coolify) - curl -fsSL https://raw.githubusercontent.com/coollabsio/coolify-cli/main/scripts/install.sh | bash + try_official || try_brew || try_go || { + echo "❌ No install method succeeded (curl / brew / go were unavailable or failed)." + echo " Try one of these manually:" + echo " • Homebrew: brew install coollabsio/coolify-cli/coolify-cli" + echo " • Go: go install github.com/coollabsio/coolify-cli/coolify@latest" + echo " • Releases: https://github.com/coollabsio/coolify-cli/releases" + exit 1 + } ;; *) echo "❌ Unsupported system: $OS" @@ -27,14 +55,15 @@ esac # Verify if command -v coolify >/dev/null 2>&1; then - echo "✅ Installed successfully: $(coolify --version)" + echo "✅ Installed successfully: $(coolify version 2>/dev/null || echo 'coolify present')" echo "" echo "Next steps:" echo " 1. Generate a token at /security/api-tokens in the Coolify Web UI" echo " 2. coolify context add -d" echo " 3. coolify context verify" else - echo "⚠️ Install script finished but coolify is still not on PATH." - echo " Check that /usr/local/bin is in \$PATH, or reopen your terminal." + echo "⚠️ Install finished but coolify is still not on PATH." + echo " - If installed via 'go install', add \"$(go env GOPATH 2>/dev/null || echo "\$HOME/go")/bin\" to your PATH." + echo " - Otherwise check that /usr/local/bin is in \$PATH, or reopen your terminal." exit 1 fi From 280a4a37c4453eabbd25e0d69f2cf97a7a4dbee6 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 20:58:52 +0800 Subject: [PATCH 11/19] =?UTF-8?q?docs(cheatsheet):=20app=20logs=20?= =?UTF-8?q?=E8=A1=A5=E5=85=85=20-f/-n,deployments=20logs=20=E8=A1=A5=20--d?= =?UTF-8?q?ebuglogs=20(issue=20#2-12)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #12:`app logs` 支持 `-n/--lines`(默认 100)与 `-f/--follow`,原 cheatsheet 只写了 `coolify app logs `。补上 -f / -n;并与 `deployments logs` 的 follow/lines 对齐说明(后者默认 0=全部,另有 --debuglogs 显示隐藏/内部构建命令)。 Co-Authored-By: Claude Opus 4.8 (1M context) --- references/cli-cheatsheet.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index f1fd4eb..87617e4 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -52,6 +52,8 @@ coolify app get # details coolify app start|stop|restart # lifecycle coolify app delete # delete (dangerous, requires confirmation; do not proactively add -f) coolify app logs # runtime logs (container stdout) +coolify app logs -f # follow runtime logs (tail -f style) +coolify app logs -n 100 # last N lines (-n/--lines, default 100) coolify app previews delete # clean up a PR preview deployment # Create a new app from a git repo / Dockerfile / image (pick the source subcommand) @@ -85,10 +87,13 @@ coolify app update \ coolify app deployments list # past deployments coolify app deployments logs # all logs from the most recent deployment coolify app deployments logs -f # follow in real time (tail -f style) -coolify app deployments logs -n 100 # last 100 lines +coolify app deployments logs -n 100 # last N lines (-n/--lines, 0 = all) +coolify app deployments logs --debuglogs # include hidden/internal build commands coolify app deployments logs # a specific deployment ``` +> Both `app logs` and `app deployments logs` share `-f`/`--follow` and `-n`/`--lines`. Difference: `app logs` defaults to 100 lines; `app deployments logs` defaults to `0` = all, and additionally supports `--debuglogs`. + **Difference between runtime logs vs deployment logs**: `app logs` shows the container's stdout after it is up and running (for troubleshooting runtime crashes); `app deployments logs` shows the build → push → startup process (for troubleshooting deployment failures). ## Deploy From c1f674d4ee1a0061f5ca0a99ab6e87e01c57345e Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 21:01:26 +0800 Subject: [PATCH 12/19] =?UTF-8?q?feat(scripts):=20=E6=96=B0=E5=A2=9E=20doc?= =?UTF-8?q?tor=20=E8=87=AA=E6=A3=80=E8=84=9A=E6=9C=AC=20(issue=20#2-13)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #13:缺少"装上先自检"入口,环境问题(CLI 太旧 / context 没连 / token 权限不足 / 缺 jq)往往操作中途才暴露。新增 scripts/doctor.sh,一屏给出四项结论: ① coolify version ≥ 已验证基线 1.6.2(sort -V 比较,不支持时降级) ② jq 是否安装 ③ context verify 连通 + 鉴权 ④ token 权限:read 探测(resource list)+ 非破坏性 deploy 探测(故意用不存在的 uuid,deploy 权限不足会先 403,有权限则 404,绝不真的部署);write / read:sensitive 说明无法无副作用探测,指向 safety-rules 已对真实实例跑通(4 项全绿,exit 0,无任何部署副作用);shellcheck severity=warning 干净。SKILL Scripts 段加"首次/排障先跑 doctor",中英 README 项目结构登记。 Co-Authored-By: Claude Opus 4.8 (1M context) --- README.md | 1 + README.zh-CN.md | 1 + SKILL.md | 3 +- scripts/doctor.sh | 93 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+), 1 deletion(-) create mode 100755 scripts/doctor.sh diff --git a/README.md b/README.md index 0bf1275..d19d30c 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,7 @@ coolify-ops/ │ ├── database-access.md # Database external access: protocol basics + internal/tunnel/hardened public + domains │ └── safety-rules.md # Destructive-operation red lines & confirmation checklist └── scripts/ + ├── doctor.sh # Preflight: CLI version / jq / connectivity / token abilities ├── install-cli.sh # Cross-platform installer for the official CLI ├── health-check.sh # One-shot health check (CLI / context / resource status) ├── deploy-and-watch.sh # Deploy + follow logs until success / failure diff --git a/README.zh-CN.md b/README.zh-CN.md index bfa371f..a2f7a91 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -129,6 +129,7 @@ coolify-ops/ │ ├── database-access.md # 数据库对外访问:协议认知 + 内网/隧道/公网加固 + 域名连库 │ └── safety-rules.md # 危险操作红线与确认清单 └── scripts/ + ├── doctor.sh # 装上先自检:CLI 版本 / jq / 连通 / token 权限 ├── install-cli.sh # 跨平台安装官方 CLI ├── health-check.sh # 一键体检(CLI / context / 资源状态) ├── deploy-and-watch.sh # 部署 + 自动跟日志直到 success / fail diff --git a/SKILL.md b/SKILL.md index 89f7589..079502e 100644 --- a/SKILL.md +++ b/SKILL.md @@ -156,7 +156,8 @@ The Web UI is still handy for first-time visual setup, dashboards/metrics, and s ## Scripts -- `scripts/install-cli.sh` — cross-platform install of the official CLI (macOS/Linux, auto-detects architecture). +- `scripts/doctor.sh [context]` — **run this first** on install or when troubleshooting. One-screen preflight: CLI version ≥ verified baseline, `jq` present, context connectivity/auth, and token abilities (a read probe + a non-destructive deploy probe that targets a bogus uuid so nothing is ever deployed). +- `scripts/install-cli.sh` — cross-platform install of the official CLI (macOS/Linux; curl → brew → go install fallback). - `scripts/health-check.sh` — one-shot health check: whether the CLI is present, whether the context connects, and the state of each resource. Run it first when troubleshooting "how's everything doing overall". - `scripts/deploy-and-watch.sh ` — triggers a deploy and automatically follows the logs, only returning once the deploy is success or failed. The default recommended way to deploy. - `scripts/gen-reference.sh` — dumps this CLI version's full command reference (via `coolify docs markdown` / `coolify docs llms`) into `references/_generated/`. Run it once after install/upgrade; treat the output as the authoritative flag source. diff --git a/scripts/doctor.sh b/scripts/doctor.sh new file mode 100755 index 0000000..9a5eac8 --- /dev/null +++ b/scripts/doctor.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +# doctor.sh — preflight self-check for coolify-ops. Run this first after install, or +# whenever something is off. Checks four things and prints a one-screen verdict: +# 1) coolify CLI present & version ≥ the verified baseline +# 2) jq present (needed to extract UUIDs / parse JSON) +# 3) context connectivity + auth (coolify context verify) +# 4) token abilities — a read probe + a non-destructive deploy probe +# Usage: bash doctor.sh [context-name] (omit the name to use the default context) +set -uo pipefail + +MIN_VER="1.6.2" +CTX_FLAG="" +if [ "${1:-}" != "" ]; then + CTX_FLAG="--context=$1" + echo "🔍 Using context: $1" +fi + +WARN=0; FAIL=0 +ok() { echo " ✅ $*"; } +warn() { echo " ⚠️ $*"; WARN=$((WARN+1)); } +bad() { echo " ❌ $*"; FAIL=$((FAIL+1)); } + +# ── 1/4 CLI + version ── +echo "── 1/4 coolify CLI ──" +if ! command -v coolify >/dev/null 2>&1; then + bad "coolify CLI not found. Run scripts/install-cli.sh first." + echo "" + echo "Cannot continue without the CLI." + exit 1 +fi +VER="$(coolify version 2>/dev/null | head -n1 | tr -d '[:space:]')" +if [ -z "$VER" ]; then + warn "installed, but couldn't read the version." +elif printf '' | sort -V >/dev/null 2>&1; then + LOWEST="$(printf '%s\n%s\n' "$VER" "$MIN_VER" | sort -V | head -n1)" + if [ "$LOWEST" = "$MIN_VER" ]; then + ok "version $VER (≥ verified baseline $MIN_VER)" + else + warn "version $VER is older than the verified baseline $MIN_VER — flags/fields may differ; consider 'coolify update'." + fi +elif [ "$VER" = "$MIN_VER" ]; then + ok "version $VER (matches verified baseline $MIN_VER)" +else + warn "version $VER (verified baseline is $MIN_VER; this 'sort' can't compare ordering)." +fi + +# ── 2/4 jq ── +echo "── 2/4 jq (JSON parsing) ──" +if command -v jq >/dev/null 2>&1; then + ok "jq present: $(jq --version 2>/dev/null)" +else + warn "jq not installed — scripts fall back to table output and can't extract UUIDs. Install: 'brew install jq' or 'apt-get install jq'." +fi + +# ── 3/4 connectivity + auth ── +echo "── 3/4 context connectivity + auth ──" +if coolify $CTX_FLAG context verify >/dev/null 2>&1; then + ok "context verified (URL reachable + token valid)" +else + bad "context verify failed. Check: URL reachable ('curl -I '), token valid (Web UI /security/api-tokens), VPS firewall." +fi + +# ── 4/4 token abilities ── +echo "── 4/4 token abilities ──" +# read probe: 'resource list' needs the 'read' ability. +if coolify $CTX_FLAG resource list --format=json >/dev/null 2>&1 &1 Date: Tue, 2 Jun 2026 21:07:44 +0800 Subject: [PATCH 13/19] =?UTF-8?q?fix(docs):=20=E7=A7=BB=E9=99=A4=20cheatsh?= =?UTF-8?q?eet=20=E8=AF=AF=E6=A0=87=E7=9A=84=E5=85=A8=E5=B1=80=20--host=20?= =?UTF-8?q?flag=20(drive-by,=20=E9=9D=9E=20issue=20#2=20=E6=9D=A1=E7=9B=AE?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修 #10 时顺带发现:全局 flag 段列了 `--host ` 用于"临时覆盖 URL",但 v1.6.2 实测 `coolify --host ... ` 直接报 `unknown flag: --host`——该 flag 不存在。v1.6.2 的 per-invocation 覆盖只有 `--context` 与 `--token`,无 URL 覆盖项。改为说明用 `--context=` 临时切换实例。 Co-Authored-By: Claude Opus 4.8 (1M context) --- references/cli-cheatsheet.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 87617e4..76786bc 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -253,8 +253,7 @@ coolify teams members list # members of the current team --format=json # for scripts/Agents to parse, used with jq --format=pretty # indented JSON, for debugging ---context= # temporarily specify a context ---host # temporarily override the URL +--context= # temporarily target a different context (the only ad-hoc way to switch instance) --token # temporarily override the token (CI scenarios) -s, --show-sensitive # show sensitive info (token/IP) --debug # print the full HTTP request/response (troubleshooting lifesaver) From c525ceb28464a8c8106844f8b020127042c10448 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 21:19:08 +0800 Subject: [PATCH 14/19] =?UTF-8?q?style:=20hero.svg=20=E7=B4=AB=E8=89=B2?= =?UTF-8?q?=E9=85=8D=E8=89=B2=E6=94=B9=E4=B8=BA=E9=9D=92=E7=BB=BF(teal)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 将 #8C52FF/#A78BFA 两支紫色全部替换为 #2DD4BF/#5EEAD4, 并同步 style 属性中重复的 rgb() 值。 Co-Authored-By: Claude Opus 4.8 (1M context) --- hero.svg | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hero.svg b/hero.svg index 1c7152f..cdb1d47 100644 --- a/hero.svg +++ b/hero.svg @@ -14,12 +14,12 @@ - - -AGENT SKILL + + +AGENT SKILL -coolify-ops - +coolify-ops + Operate your VPS in plain English. @@ -39,9 +39,9 @@ coolify-ops — zsh -~/my-next-app claude -deploy this Next.js app to my SG VPS -coolify-ops · Next.js detected +~/my-next-app claude +deploy this Next.js app to my SG VPS +coolify-ops · Next.js detected $ coolify context use sg-vps $ coolify app env sync .env.prod $ coolify deploy name my-next-app From a2ab8f0deae06fb0655c4f0d267b1ccd468f2d75 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 23:11:24 +0800 Subject: [PATCH 15/19] =?UTF-8?q?docs:=20=E4=B8=BA=20init/firewall/common?= =?UTF-8?q?=20=E8=A1=A5=E6=AD=A3=E5=BC=8F=20[ALPHA]=20=E6=AE=B5=E8=90=BD?= =?UTF-8?q?=20(issue=20#2-08=20=E6=94=B6=E5=B0=BE)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 按用户批准,把 #08 原先的 inline caveat 升级为显著标注的 [ALPHA] 段落: 明确列出 init(WireGuard mesh + Podman 引导)/ firewall(COOLIFY-ALLOW iptables 链、跨主机容器规则)/ common sshmesh 这组走 SSH+root 的 Coolify v5 路线图命令, 并强调它们**不在已验证的 v1.6.2 二进制中**(`coolify --help` 无此命令)、本 skill 不使用也不当作可用功能文档化、使用前需对照自己的 CLI 构建核实;同时重申:加固 公网 DB 端口源 IP 仍用 ufw/云安全组,与(未来的)firewall 管 mesh 容器规则不是 一回事。不为 v1.6.2 里不存在的命令编造可用 flag。 Co-Authored-By: Claude Opus 4.8 (1M context) --- SKILL.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/SKILL.md b/SKILL.md index 079502e..385fc61 100644 --- a/SKILL.md +++ b/SKILL.md @@ -10,7 +10,12 @@ Remotely operate a Coolify instance through the official `coolify` CLI (the Go v ## Core Principles 1. **For everything in this skill's scope, the CLI is an HTTP API client — not SSH.** All the operations covered here (deploy / app / service / database / env / logs / backup — the entire v1.6.2 command surface) go through the Coolify REST API with a Bearer token; they have nothing to do with the server's SSH credentials. If a command can't connect, suspect API reachability and the token first, not SSH. - - *Caveat (out of scope):* some experimental, not-yet-GA commands in newer dev builds (WireGuard mesh / firewall bootstrapping for the upcoming Coolify v5) do run over SSH + root — but they are **not present in v1.6.2** and are not part of this skill. So don't over-generalize "the CLI never uses SSH" on a future build; and don't confuse such a future `firewall` command (which manages mesh container rules) with hardening a public database port — restricting a DB port's source IPs is still done with `ufw` / your cloud security group (see `references/database-access.md` §2.3). + > **`[ALPHA]` — experimental Coolify v5 commands, out of scope here.** The Coolify v5 roadmap adds SSH-based bootstrap commands that, unlike everything above, run over **SSH + root**: + > - `init` — provisions a host (WireGuard mesh + Podman) over SSH. + > - `firewall` — manages a `COOLIFY-ALLOW` iptables chain / cross-host container rules over SSH. + > - `common sshmesh` — the underlying SSH-mesh plumbing. + > + > ⚠️ These are **not present in the verified v1.6.2 binary** (`coolify --help` does not list them), so this skill neither uses nor documents them as usable — treat any such command as experimental, root-level, and not a stable feature; verify against your own CLI build before touching it. In particular, **do not confuse a future `firewall` command (which manages mesh container rules) with hardening a public database port** — restricting a public DB port's source IPs is still done with `ufw` / your cloud security group, which is a different thing entirely (see `references/database-access.md` §2.3). 2. **The CLI is self-documenting — `--help` (or a generated reference) is the source of truth for flags.** The CLI keeps evolving and flags change. The authoritative flag values are whatever `coolify --help` prints, or a version-exact reference generated by `scripts/gen-reference.sh` (which runs `coolify docs markdown` / `coolify docs llms` into `references/_generated/`). The hand-maintained `references/cli-cheatsheet.md` is only a high-frequency quick reference (+ jq recipes + troubleshooting table) and can drift — never guess flags from memory. Common levels: ```bash From 32f35d3ca3961a0b8ecf0fd457b95911cb7f0b1a Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Tue, 2 Jun 2026 23:24:55 +0800 Subject: [PATCH 16/19] =?UTF-8?q?fix:=20=E5=A4=84=E7=90=86=20Codex=20revie?= =?UTF-8?q?w=20=E7=9A=84=E4=B8=A4=E6=9D=A1=20P2=20(PR=20#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 经本机 v1.6.2 --help 复核,两条均属实,已修: 1. database env 并非"与 app/service 一致"(cli-cheatsheet):实测 `database env sync` 只有 `-f/--file` + `--is-literal`,`database env create` 也无 `--build-time/--runtime/--preview`(数据库无 build 步骤)。原"identical across app/service/database"会让 Agent 跑 `database env sync --build-time=false` 得到 unknown-flag。改为明确标注 database env 是 reduced 集。 2. doctor.sh 版本比较未归一化前导 v:`coolify version` 在部分构建会返回 `v1.6.2`, `sort -V` 会把 `1.6.2` 排在任何 `v1.x.y` 之前,导致 v1.6.1 用户被误判为 ">= baseline"(恰恰在最易 flag drift 的旧版本上失效)。比较前 `${VER#v}` 去掉 可选前导 v(已用 v1.6.1/1.6.1/v1.6.2/v1.7.0 验证判定正确)。 Co-Authored-By: Claude Opus 4.8 (1M context) --- references/cli-cheatsheet.md | 6 +++--- scripts/doctor.sh | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index 76786bc..eaeffc1 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -112,7 +112,7 @@ coolify deploy cancel # cancel an in-progress deployment ## Env -> The env subcommands are identical across **app, service, and database** (e.g. `coolify database env list `, `coolify database env sync --file .env`); the examples below use app. +> The env subcommands exist for **app, service, and database**. App and service share the full flag set (incl. `--build-time` / `--runtime` / `--preview`). **Database env is reduced** — a database has no build step, so `database env sync` only takes `-f`/`--file` + `--is-literal`, and `database env create` has no `--build-time`/`--runtime`/`--preview` either (passing them errors with `unknown flag`). The examples below use app. ```bash coolify app env list @@ -159,9 +159,9 @@ coolify database backup create \ coolify database backup trigger # back up immediately coolify database backup executions # backup execution records -# databases also have env and storage subcommands (same shape as app): +# databases also have env (reduced flags — no --build-time/--runtime/--preview) and storage: coolify database env list -coolify database env sync --file .env # see Env section for flag caveats +coolify database env sync --file .env # only -f/--file + --is-literal coolify database storage list # see Storage section ``` diff --git a/scripts/doctor.sh b/scripts/doctor.sh index 9a5eac8..c314d30 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -29,16 +29,17 @@ if ! command -v coolify >/dev/null 2>&1; then exit 1 fi VER="$(coolify version 2>/dev/null | head -n1 | tr -d '[:space:]')" +VER_NUM="${VER#v}" # strip an optional leading 'v' — some builds report 'v1.6.2' if [ -z "$VER" ]; then warn "installed, but couldn't read the version." elif printf '' | sort -V >/dev/null 2>&1; then - LOWEST="$(printf '%s\n%s\n' "$VER" "$MIN_VER" | sort -V | head -n1)" + LOWEST="$(printf '%s\n%s\n' "$VER_NUM" "$MIN_VER" | sort -V | head -n1)" if [ "$LOWEST" = "$MIN_VER" ]; then ok "version $VER (≥ verified baseline $MIN_VER)" else warn "version $VER is older than the verified baseline $MIN_VER — flags/fields may differ; consider 'coolify update'." fi -elif [ "$VER" = "$MIN_VER" ]; then +elif [ "$VER_NUM" = "$MIN_VER" ]; then ok "version $VER (matches verified baseline $MIN_VER)" else warn "version $VER (verified baseline is $MIN_VER; this 'sort' can't compare ordering)." From 69d3ad98e4506ab5e4d353f6aa233bad1e161b6e Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Wed, 3 Jun 2026 00:19:41 +0800 Subject: [PATCH 17/19] =?UTF-8?q?fix:=20=E8=AE=A2=E6=AD=A3=20app=20storage?= =?UTF-8?q?=20update=20=E8=AF=AD=E6=B3=95=20(Codex=20review,=20PR=20#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 经本机 v1.6.2 --help 复核属实:`app storage update` 只接受一个位置参数 ``,storage 标识必须用 `--uuid `(`--id` 已弃用), 原 cheatsheet 写成第二个位置参数会直接失败。改为 `coolify app storage update --uuid --type ...`。 注:`app storage delete ` 经核实确实是两个位置参数 (Codex 也未误报),保留并补注两者差异。 Co-Authored-By: Claude Opus 4.8 (1M context) --- references/cli-cheatsheet.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/references/cli-cheatsheet.md b/references/cli-cheatsheet.md index eaeffc1..cbb48a9 100644 --- a/references/cli-cheatsheet.md +++ b/references/cli-cheatsheet.md @@ -227,8 +227,8 @@ Persistent volumes / file mounts for stateful resources — same shape for `app` coolify app storage list coolify app storage create --type persistent --name --mount-path /data coolify app storage create --type file --mount-path /etc/app/config.yml --content "$(cat config.yml)" -coolify app storage update ... -coolify app storage delete # dangerous: may delete persisted data +coolify app storage update --uuid --type persistent --mount-path /data # update: storage id is --uuid, NOT a 2nd positional +coolify app storage delete # delete: storage id IS a 2nd positional (dangerous: may delete persisted data) # database / service are identical — just swap the noun: coolify database storage list From afc16431d1020d754e7c14fb6258ed697b111741 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:27:09 +0000 Subject: [PATCH 18/19] =?UTF-8?q?fix:=20code=20review=20=E2=80=94=20?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3=208=20=E5=A4=84=E9=97=AE=E9=A2=98(=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=E6=8B=BC=E5=86=99/=E7=BC=BA=E5=8F=82/=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=BC=95=E7=94=A8/jq=20=E5=8C=B9=E9=85=8D/=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E5=89=8D=E7=BC=80/sslmode=20=E6=8F=8F=E8=BF=B0/?= =?UTF-8?q?=E5=B9=B4=E4=BB=BD)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.zh-CN.md | 2 +- SKILL.md | 2 +- references/database-access.md | 2 +- references/safety-rules.md | 4 ++-- scripts/deploy-and-watch.sh | 35 +++++++++++++++++++---------------- scripts/doctor.sh | 12 ++++++------ scripts/gen-reference.sh | 3 ++- scripts/health-check.sh | 18 +++++++++--------- 8 files changed, 41 insertions(+), 37 deletions(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index a2f7a91..f6ae54d 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -138,4 +138,4 @@ coolify-ops/ ## License -[MIT](LICENSE) © 2025 hifizz +[MIT](LICENSE) © 2026 hifizz diff --git a/SKILL.md b/SKILL.md index 385fc61..9da4582 100644 --- a/SKILL.md +++ b/SKILL.md @@ -36,7 +36,7 @@ Remotely operate a Coolify instance through the official `coolify` CLI (the Go v ```bash # 1. Check whether it's already installed -coolify --version || bash scripts/install-cli.sh +coolify version || bash scripts/install-cli.sh # 2. Check whether a context already exists coolify context list diff --git a/references/database-access.md b/references/database-access.md index 6270dbb..8a6ec76 100644 --- a/references/database-access.md +++ b/references/database-access.md @@ -127,7 +127,7 @@ postgresql://user:pass@db.example.com:5432/mydb **The database containers Coolify starts by default usually do not have SSL/TLS enabled.** This means: - A plaintext connection over the public internet exposes the **account, password, and query data** entirely on the wire, and any intermediate hop can sniff it. -- **Do not assume the connection is encrypted.** Writing `sslmode=require` in the connection string does not mean the server actually supports it — if the database has no certificate configured, it will either fail to connect or silently downgrade. +- **Do not assume the connection is encrypted.** Writing `sslmode=require` in the connection string tells the *client* to demand TLS — if the database has no certificate configured, the connection will **fail** (which is the safe outcome). But weaker modes like `sslmode=prefer` may silently fall back to plaintext, giving a false sense of security. Therefore: diff --git a/references/safety-rules.md b/references/safety-rules.md index fcb91c2..8caeda5 100644 --- a/references/safety-rules.md +++ b/references/safety-rules.md @@ -8,11 +8,11 @@ This skill operates on **real resources in production environments**. The follow | Operation | Consequence | Must do before executing | |---|---|---| -| `coolify database delete ` | Deletes the database; data may be permanently lost | 1. Confirm there is a recent backup: `coolify database backup executions`; 2. Restate the database name to the user; 3. Wait for an explicit "confirm delete" | +| `coolify database delete ` | Deletes the database; data may be permanently lost | 1. Confirm there is a recent backup: `coolify database backup executions `; 2. Restate the database name to the user; 3. Wait for an explicit "confirm delete" | | `coolify app delete ` | Deletes the app and its configuration | Restate the app name + confirm; remind about associated data/volumes | | `coolify service delete ` | Deletes the service | Restate the service name + confirm | | `coolify context delete ` | Deletes the local connection config | Confirm whether you still need to manage that instance | -| `coolify app env delete` | Deletes an environment variable | Confirm that the variable has no references in use | +| `coolify app env delete ` | Deletes an environment variable | Confirm that the variable has no references in use | | Any command with `--delete-volumes` | Deletes data volumes | This is data destruction, the highest level of confirmation | ### 🟡 Caution: affects live availability, requires confirmation in production diff --git a/scripts/deploy-and-watch.sh b/scripts/deploy-and-watch.sh index 01e6c89..80db6df 100644 --- a/scripts/deploy-and-watch.sh +++ b/scripts/deploy-and-watch.sh @@ -6,7 +6,7 @@ # bash deploy-and-watch.sh --context staging set -uo pipefail -CTX_FLAG="" +CTX_ARGS=() BY_UUID=0 TARGET="" @@ -14,7 +14,7 @@ TARGET="" while [ $# -gt 0 ]; do case "$1" in --uuid) BY_UUID=1; TARGET="$2"; shift 2 ;; - --context) CTX_FLAG="--context=$2"; shift 2 ;; + --context) CTX_ARGS=(--context="$2"); shift 2 ;; *) TARGET="$1"; shift ;; esac done @@ -28,30 +28,33 @@ fi command -v coolify >/dev/null 2>&1 || { echo "❌ coolify CLI not found"; exit 1; } # Resolve the app uuid (following logs requires a uuid) -APP_UUID="$TARGET" -if [ "$BY_UUID" -eq 0 ]; then - if command -v jq >/dev/null 2>&1; then - APP_UUID="$(coolify $CTX_FLAG app list --format=json 2>/dev/null \ - | jq -r --arg n "$TARGET" '.[] | select(.name==$n) | .uuid' | head -n1)" - fi +APP_UUID="" +if [ "$BY_UUID" -eq 1 ]; then + APP_UUID="$TARGET" +elif command -v jq >/dev/null 2>&1; then + APP_UUID="$(coolify "${CTX_ARGS[@]}" app list --format=json 2>/dev/null \ + | jq -r --arg n "$TARGET" '.[] | select(.name==$n) | .uuid' | head -n1)" if [ -z "$APP_UUID" ] || [ "$APP_UUID" = "null" ]; then - echo "⚠️ Could not resolve a uuid from name '$TARGET' (jq may not be installed or the name does not match)." + echo "⚠️ Could not resolve a uuid from name '$TARGET' (the name may not match any app)." echo " Deployment will still be triggered by name, but logs cannot be followed automatically." APP_UUID="" fi +else + echo "⚠️ jq not installed — cannot resolve uuid from name '$TARGET'." + echo " Deployment will still be triggered by name, but logs cannot be followed automatically." fi # Trigger the deployment echo "🚀 Triggering deployment: $TARGET" if [ "$BY_UUID" -eq 1 ]; then - coolify $CTX_FLAG deploy uuid "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } + coolify "${CTX_ARGS[@]}" deploy uuid "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } else - coolify $CTX_FLAG deploy name "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } + coolify "${CTX_ARGS[@]}" deploy name "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } fi if [ -z "$APP_UUID" ]; then echo "ℹ️ No uuid, cannot follow automatically. Check manually:" - echo " coolify $CTX_FLAG deploy list" + echo " coolify deploy list" exit 0 fi @@ -59,7 +62,7 @@ fi echo "" echo "📜 Following deployment logs (Ctrl-C stops following; the deployment keeps running in the background)..." echo "────────────────────────────────────────" -coolify $CTX_FLAG app deployments logs "$APP_UUID" -f +coolify "${CTX_ARGS[@]}" app deployments logs "$APP_UUID" -f # After following ends, report the final status. # Use `app deployments list ` — it is already scoped to this app, so we @@ -69,10 +72,10 @@ coolify $CTX_FLAG app deployments logs "$APP_UUID" -f echo "────────────────────────────────────────" echo "🔎 Latest deployment status:" if command -v jq >/dev/null 2>&1; then - coolify $CTX_FLAG app deployments list "$APP_UUID" --format=json 2>/dev/null \ + coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" --format=json 2>/dev/null \ | jq -r 'sort_by(.created_at) | last | " Status: \(.status // "unknown") Deployment ID: \(.deployment_uuid // .uuid // "?")"' \ - 2>/dev/null || coolify $CTX_FLAG app deployments list "$APP_UUID" + 2>/dev/null || coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" else - coolify $CTX_FLAG app deployments list "$APP_UUID" + coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" fi diff --git a/scripts/doctor.sh b/scripts/doctor.sh index c314d30..ada3f9e 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -9,9 +9,9 @@ set -uo pipefail MIN_VER="1.6.2" -CTX_FLAG="" +CTX_ARGS=() if [ "${1:-}" != "" ]; then - CTX_FLAG="--context=$1" + CTX_ARGS=(--context="$1") echo "🔍 Using context: $1" fi @@ -55,7 +55,7 @@ fi # ── 3/4 connectivity + auth ── echo "── 3/4 context connectivity + auth ──" -if coolify $CTX_FLAG context verify >/dev/null 2>&1; then +if coolify "${CTX_ARGS[@]}" context verify >/dev/null 2>&1; then ok "context verified (URL reachable + token valid)" else bad "context verify failed. Check: URL reachable ('curl -I '), token valid (Web UI /security/api-tokens), VPS firewall." @@ -64,10 +64,10 @@ fi # ── 4/4 token abilities ── echo "── 4/4 token abilities ──" # read probe: 'resource list' needs the 'read' ability. -if coolify $CTX_FLAG resource list --format=json >/dev/null 2>&1 /dev/null 2>&1 &1 &1 &1 /dev/null 2>&1 || { echo "❌ coolify CLI not found. Run install-cli.sh first."; exit 1; } VER="$(coolify version 2>/dev/null | head -n1 || echo unknown)" -echo "📚 Generating reference from coolify CLI v${VER} → references/_generated/" +VER_DISPLAY="${VER#v}" # strip optional leading 'v' for display +echo "📚 Generating reference from coolify CLI v${VER_DISPLAY} → references/_generated/" mkdir -p "$OUT_DIR" # Markdown docs (one file per command tree) — human + agent readable diff --git a/scripts/health-check.sh b/scripts/health-check.sh index 90eef2f..3b46301 100644 --- a/scripts/health-check.sh +++ b/scripts/health-check.sh @@ -5,9 +5,9 @@ # Omit context-name to use the default context set -uo pipefail -CTX_FLAG="" +CTX_ARGS=() if [ "${1:-}" != "" ]; then - CTX_FLAG="--context=$1" + CTX_ARGS=(--context="$1") echo "🔍 Using context: $1" fi @@ -17,12 +17,12 @@ if ! command -v coolify >/dev/null 2>&1; then echo "❌ coolify CLI not found. Run install-cli.sh first" exit 1 fi -echo "✅ $(coolify --version 2>/dev/null || echo coolify present)" +echo "✅ $(coolify version 2>/dev/null || echo coolify present)" # 2. Is the context reachable echo "" echo "── 2/4 Verifying connection ──" -if ! coolify $CTX_FLAG context verify 2>&1; then +if ! coolify "${CTX_ARGS[@]}" context verify 2>&1; then echo "❌ Context verification failed. Troubleshooting:" echo " - Is the URL correct and reachable (curl -I )" echo " - Is the token valid (Web UI /security/api-tokens)" @@ -33,19 +33,19 @@ fi # 3. Backend version echo "" echo "── 3/4 Coolify backend version ──" -coolify $CTX_FLAG context version 2>/dev/null || echo "(version query skipped)" +coolify "${CTX_ARGS[@]}" context version 2>/dev/null || echo "(version query skipped)" # 4. Resource status overview echo "" echo "── 4/4 Resource status ──" if command -v jq >/dev/null 2>&1; then - RES="$(coolify $CTX_FLAG resources list --format=json 2>/dev/null)" + RES="$(coolify "${CTX_ARGS[@]}" resources list --format=json 2>/dev/null)" if [ -n "$RES" ] && echo "$RES" | jq empty 2>/dev/null; then TOTAL=$(echo "$RES" | jq 'length') echo "Total resources: $TOTAL" echo "" echo "⚠️ Resources not in running state:" - UNHEALTHY=$(echo "$RES" | jq -r '.[] | select(.status != null and (.status | test("running") | not)) | " - \(.name): \(.status)"') + UNHEALTHY=$(echo "$RES" | jq -r '.[] | select(.status != null and .status != "running") | " - \(.name): \(.status)"') if [ -z "$UNHEALTHY" ]; then echo " (none, all healthy ✅)" else @@ -53,11 +53,11 @@ if command -v jq >/dev/null 2>&1; then fi else echo "(response is not valid JSON, falling back to table output)" - coolify $CTX_FLAG resources list + coolify "${CTX_ARGS[@]}" resources list fi else echo "(jq not installed, printing table output directly)" - coolify $CTX_FLAG resources list + coolify "${CTX_ARGS[@]}" resources list fi echo "" From 02c3e413de8c87195d949ea93dfc11a604e5af00 Mon Sep 17 00:00:00 2001 From: zilin <276161014@qq.com> Date: Wed, 3 Jun 2026 01:43:09 +0800 Subject: [PATCH 19/19] =?UTF-8?q?fix:=20=E8=AE=A2=E6=AD=A3=20Copilot=20cod?= =?UTF-8?q?e=20review=20=E5=BC=95=E5=85=A5=E7=9A=84=E4=B8=A4=E5=A4=84=20re?= =?UTF-8?q?gression=20(PR=20#3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copilot 的 afc1643 共 8 处改动,其中 6 处正确(命令拼写/缺参/sslmode 描述/ deploy-and-watch 解析逻辑/版本前缀/年份)予以保留;两处经实测为 regression,本提交修正: 1. health-check.sh 的 jq 匹配:`.status != "running"` 会把真实状态 `running:healthy` / `running:unknown`(实例实测值)全部误报为"not running"。改为 `(.status | startswith("running") | not)`——比原 `test("running")` 子串匹配更精确, 且能正确放过所有 running:* 状态。 2. 三个脚本的 `"${CTX_ARGS[@]}"` 数组写法:在 macOS 默认 `/bin/bash` 3.2 上, `set -u` 展开空数组会报 `unbound variable` 直接崩溃(env bash → /bin/bash 3.2)。 实测 Copilot 版 doctor.sh 不带 context 参数跑到第 3 步即 exit。改回 `CTX_FLAG=""` 字符串惯用法(兼容 bash 3.2;SC2086 仅 info 级,CI severity=warning 通过)。保留 Copilot 对 deploy-and-watch 解析逻辑的改进。 验证:三脚本 shellcheck --severity=warning 干净;doctor.sh / health-check.sh 在 /bin/bash 3.2、不带参数下均 exit 0 正常运行,health-check 正确识别 running:* 为健康。 Co-Authored-By: Claude Opus 4.8 (1M context) --- scripts/deploy-and-watch.sh | 20 ++++++++++---------- scripts/doctor.sh | 12 ++++++------ scripts/health-check.sh | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/scripts/deploy-and-watch.sh b/scripts/deploy-and-watch.sh index 80db6df..8a45d97 100644 --- a/scripts/deploy-and-watch.sh +++ b/scripts/deploy-and-watch.sh @@ -6,7 +6,7 @@ # bash deploy-and-watch.sh --context staging set -uo pipefail -CTX_ARGS=() +CTX_FLAG="" BY_UUID=0 TARGET="" @@ -14,7 +14,7 @@ TARGET="" while [ $# -gt 0 ]; do case "$1" in --uuid) BY_UUID=1; TARGET="$2"; shift 2 ;; - --context) CTX_ARGS=(--context="$2"); shift 2 ;; + --context) CTX_FLAG="--context=$2"; shift 2 ;; *) TARGET="$1"; shift ;; esac done @@ -32,7 +32,7 @@ APP_UUID="" if [ "$BY_UUID" -eq 1 ]; then APP_UUID="$TARGET" elif command -v jq >/dev/null 2>&1; then - APP_UUID="$(coolify "${CTX_ARGS[@]}" app list --format=json 2>/dev/null \ + APP_UUID="$(coolify $CTX_FLAG app list --format=json 2>/dev/null \ | jq -r --arg n "$TARGET" '.[] | select(.name==$n) | .uuid' | head -n1)" if [ -z "$APP_UUID" ] || [ "$APP_UUID" = "null" ]; then echo "⚠️ Could not resolve a uuid from name '$TARGET' (the name may not match any app)." @@ -47,14 +47,14 @@ fi # Trigger the deployment echo "🚀 Triggering deployment: $TARGET" if [ "$BY_UUID" -eq 1 ]; then - coolify "${CTX_ARGS[@]}" deploy uuid "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } + coolify $CTX_FLAG deploy uuid "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } else - coolify "${CTX_ARGS[@]}" deploy name "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } + coolify $CTX_FLAG deploy name "$TARGET" || { echo "❌ Failed to trigger deployment"; exit 1; } fi if [ -z "$APP_UUID" ]; then echo "ℹ️ No uuid, cannot follow automatically. Check manually:" - echo " coolify deploy list" + echo " coolify $CTX_FLAG deploy list" exit 0 fi @@ -62,7 +62,7 @@ fi echo "" echo "📜 Following deployment logs (Ctrl-C stops following; the deployment keeps running in the background)..." echo "────────────────────────────────────────" -coolify "${CTX_ARGS[@]}" app deployments logs "$APP_UUID" -f +coolify $CTX_FLAG app deployments logs "$APP_UUID" -f # After following ends, report the final status. # Use `app deployments list ` — it is already scoped to this app, so we @@ -72,10 +72,10 @@ coolify "${CTX_ARGS[@]}" app deployments logs "$APP_UUID" -f echo "────────────────────────────────────────" echo "🔎 Latest deployment status:" if command -v jq >/dev/null 2>&1; then - coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" --format=json 2>/dev/null \ + coolify $CTX_FLAG app deployments list "$APP_UUID" --format=json 2>/dev/null \ | jq -r 'sort_by(.created_at) | last | " Status: \(.status // "unknown") Deployment ID: \(.deployment_uuid // .uuid // "?")"' \ - 2>/dev/null || coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" + 2>/dev/null || coolify $CTX_FLAG app deployments list "$APP_UUID" else - coolify "${CTX_ARGS[@]}" app deployments list "$APP_UUID" + coolify $CTX_FLAG app deployments list "$APP_UUID" fi diff --git a/scripts/doctor.sh b/scripts/doctor.sh index ada3f9e..c314d30 100755 --- a/scripts/doctor.sh +++ b/scripts/doctor.sh @@ -9,9 +9,9 @@ set -uo pipefail MIN_VER="1.6.2" -CTX_ARGS=() +CTX_FLAG="" if [ "${1:-}" != "" ]; then - CTX_ARGS=(--context="$1") + CTX_FLAG="--context=$1" echo "🔍 Using context: $1" fi @@ -55,7 +55,7 @@ fi # ── 3/4 connectivity + auth ── echo "── 3/4 context connectivity + auth ──" -if coolify "${CTX_ARGS[@]}" context verify >/dev/null 2>&1; then +if coolify $CTX_FLAG context verify >/dev/null 2>&1; then ok "context verified (URL reachable + token valid)" else bad "context verify failed. Check: URL reachable ('curl -I '), token valid (Web UI /security/api-tokens), VPS firewall." @@ -64,10 +64,10 @@ fi # ── 4/4 token abilities ── echo "── 4/4 token abilities ──" # read probe: 'resource list' needs the 'read' ability. -if coolify "${CTX_ARGS[@]}" resource list --format=json >/dev/null 2>&1 /dev/null 2>&1 &1 &1 &1 /dev/null || echo coolify present)" # 2. Is the context reachable echo "" echo "── 2/4 Verifying connection ──" -if ! coolify "${CTX_ARGS[@]}" context verify 2>&1; then +if ! coolify $CTX_FLAG context verify 2>&1; then echo "❌ Context verification failed. Troubleshooting:" echo " - Is the URL correct and reachable (curl -I )" echo " - Is the token valid (Web UI /security/api-tokens)" @@ -33,19 +33,19 @@ fi # 3. Backend version echo "" echo "── 3/4 Coolify backend version ──" -coolify "${CTX_ARGS[@]}" context version 2>/dev/null || echo "(version query skipped)" +coolify $CTX_FLAG context version 2>/dev/null || echo "(version query skipped)" # 4. Resource status overview echo "" echo "── 4/4 Resource status ──" if command -v jq >/dev/null 2>&1; then - RES="$(coolify "${CTX_ARGS[@]}" resources list --format=json 2>/dev/null)" + RES="$(coolify $CTX_FLAG resources list --format=json 2>/dev/null)" if [ -n "$RES" ] && echo "$RES" | jq empty 2>/dev/null; then TOTAL=$(echo "$RES" | jq 'length') echo "Total resources: $TOTAL" echo "" echo "⚠️ Resources not in running state:" - UNHEALTHY=$(echo "$RES" | jq -r '.[] | select(.status != null and .status != "running") | " - \(.name): \(.status)"') + UNHEALTHY=$(echo "$RES" | jq -r '.[] | select(.status != null and (.status | startswith("running") | not)) | " - \(.name): \(.status)"') if [ -z "$UNHEALTHY" ]; then echo " (none, all healthy ✅)" else @@ -53,11 +53,11 @@ if command -v jq >/dev/null 2>&1; then fi else echo "(response is not valid JSON, falling back to table output)" - coolify "${CTX_ARGS[@]}" resources list + coolify $CTX_FLAG resources list fi else echo "(jq not installed, printing table output directly)" - coolify "${CTX_ARGS[@]}" resources list + coolify $CTX_FLAG resources list fi echo ""