docs: apps.create pathways, volumes tools, stale-volume cookbook (v2.3)
Documents the new image/composeRaw apps.create pathways with guidance on when to use each (third-party SaaS vs user code). Adds sections on choosing the right pathway and the canonical stale-volume recovery flow using apps.volumes.list + apps.volumes.wipe + apps.exec. Renumbers troubleshooting sections 11.4-11.9 to accommodate the new entries without disrupting existing content. Made-with: Cursor
This commit is contained in:
@@ -109,13 +109,15 @@ Version: **2.1.0**.
|
||||
|---|---|---|
|
||||
| `apps.list` | All Coolify apps in the workspace. | — |
|
||||
| `apps.get` | Single app details (status, fqdn, domains, git info). | `{ uuid }` |
|
||||
| `apps.create` | Create a Coolify app from a Gitea repo in the workspace's org. Clones over **HTTPS with the workspace bot's PAT embedded in the URL** — SSH is not used because Gitea's SSH isn't reachable on the default port. Auto-domain `{name}.{slug}.vibnai.com`. | `{ repo, branch?, name?, ports?, buildPack?, domain?, envs?, instantDeploy?, dockerComposeLocation?, dockerfileLocation?, baseDirectory? }` |
|
||||
| `apps.create` | Create a Coolify app. **Three pathways** depending on the source — choose the right one for the job: **(1) Gitea repo** (user's own code): pass `repo`. Clones over HTTPS+PAT; no SSH. **(2) Docker image** (pre-built third-party app, e.g. `nginx:alpine`): pass `image`. No repo created. **(3) Inline Docker Compose YAML** (multi-service third-party app, e.g. Twenty, Directus): pass `composeRaw` with the full compose YAML as a string. No repo created. Use pathways 2 and 3 for any third-party SaaS app — they are faster, simpler, and avoid stale-git-state issues. Auto-domain `{name}.{slug}.vibnai.com` for all pathways. | **Pathway 1 (repo):** `{ repo, branch?, name?, ports?, buildPack?, domain?, envs?, instantDeploy?, dockerComposeLocation?, dockerfileLocation?, baseDirectory? }` **Pathway 2 (image):** `{ image, name?, ports?, domain?, envs?, instantDeploy? }` **Pathway 3 (compose):** `{ composeRaw, name?, domain?, composeService?, composeDomains?, envs?, instantDeploy? }` — `composeDomains` is `[{ service, domain }]`; defaults to `[{ service: "server", domain: auto }]` |
|
||||
| `apps.update` | PATCH a whitelisted set of fields (name, description, git branch/commit, ports, build commands, base directory, Dockerfile location, docker-compose location…). Returns `applied`, `ignored`, and `rerouted` arrays so the agent can see exactly what persisted; setting `fqdn`/`domains`/`docker_compose_domains` returns a `rerouted` entry pointing at `apps.domains.set`, and setting `git_repository` returns one pointing at `apps.rewire_git`. | `{ uuid, patch }` |
|
||||
| `apps.rewire_git` | Re-point an app's `git_repository` at the canonical HTTPS+PAT clone URL. Use to recover older apps that were created with SSH URLs, or to refresh a rotated bot PAT. | `{ uuid, repo? }` — `repo` optional; inferred from current URL if omitted |
|
||||
| `apps.delete` | Destroy the app. Volumes kept by default. | `{ uuid, confirm }` — `confirm` must equal the app's exact name |
|
||||
| `apps.deploy` | Trigger a new deployment. | `{ uuid, force? }` |
|
||||
| `apps.deployments` | List recent deployments + status. | `{ uuid }` |
|
||||
| `apps.logs` | Runtime logs for a running app. Compose-aware: returns per-service logs for `dockercompose` build packs, single stream for `dockerfile`/`nixpacks`. Includes container status and any diagnostic warnings. | `{ uuid, service?, lines? }` — `service` filter (compose only), `lines` default 200, max 5000 |
|
||||
| `apps.volumes.list` | List Docker volumes belonging to an app (name + size in bytes). Use before `apps.volumes.wipe` to know exact volume names. | `{ uuid }` |
|
||||
| `apps.volumes.wipe` | **Destructive / irreversible.** Stop all app containers, remove a specific volume, leave it ready for a fresh `apps.deploy`. Use to recover from stale DB state on first boot (the most common compose app failure). `confirm` must equal the exact volume name. | `{ uuid, volume, confirm }` |
|
||||
| `apps.exec` | Run a one-shot command inside an app container (via `docker exec` on the Coolify host). Compose-aware: pass `service` when the app has >1 container. Returns `{ container, service, code, stdout, stderr, truncated, durationMs, containerHealth }`. Default timeout 60s (max 10 min); default output cap 1 MB (max 5 MB). Command is run through `sh -lc` so shell syntax works. Use this for database migrations, seeds, CLI invocations, and ad-hoc debugging. Every call is audit-logged (command + target, not output). | `{ uuid, command, service?, user?, workdir?, timeout_ms?, max_bytes? }` |
|
||||
| `apps.domains.list` | Current domain set. | `{ uuid }` |
|
||||
| `apps.domains.set` | Replace the domain set. All entries must end with `.{slug}.vibnai.com`. Compose-aware: for `dockercompose` apps the domain is attached to a specific service (`server` by default; override with `service`). | `{ uuid, domains: string[], service? }` |
|
||||
@@ -581,7 +583,7 @@ The MCP descriptor at `GET /api/mcp` reports a semver `version`. Tool names
|
||||
are append-only within a major version — agents can cache the tool list
|
||||
safely for the duration of a conversation but should re-fetch on 404.
|
||||
|
||||
Current version: **2.2.0**.
|
||||
Current version: **2.3.0**.
|
||||
|
||||
- **1.x** — session-cookie-only MCP, no tenant keys.
|
||||
- **2.0** — `vibn_sk_…` keys, workspace-scoped Gitea bot + Coolify project.
|
||||
@@ -590,6 +592,9 @@ Current version: **2.2.0**.
|
||||
- **2.2** — per-workspace GCS object storage (`storage.*`), compose-aware
|
||||
domain routing, runtime log tailing (`apps.logs`), in-container command
|
||||
execution (`apps.exec`), and diagnostic `apps.update` responses.
|
||||
- **2.3** — `apps.create` Docker-image and inline-composeRaw pathways (no
|
||||
Gitea repo required for third-party apps), `apps.volumes.list` +
|
||||
`apps.volumes.wipe` for self-service volume recovery.
|
||||
|
||||
---
|
||||
|
||||
@@ -654,7 +659,50 @@ single-container apps use `domains` (comma-separated string).
|
||||
3. `apps.logs { uuid, service: "server", lines: 200 }` — look for
|
||||
startup errors like `EADDRINUSE` or config failures.
|
||||
|
||||
### 11.4 "Healthcheck times out on first deploy"
|
||||
### 11.4 "Choosing the right `apps.create` pathway"
|
||||
|
||||
| Situation | Use |
|
||||
|---|---|
|
||||
| User's own code lives in their Gitea org | `repo` (pathway 1) |
|
||||
| Single-container third-party app (nginx, redis, a docker image) | `image` (pathway 2) |
|
||||
| Multi-service third-party app (Twenty, Directus, Cal.com, Plane…) | `composeRaw` (pathway 3) |
|
||||
|
||||
**Never** create a Gitea repo just to host a third-party app's compose file. Use `composeRaw` instead — it's faster, has no git-clone overhead, and avoids the partial-state problems that can happen when Coolify clones a fork.
|
||||
|
||||
For `composeRaw`, fetch the app's official `docker-compose.yml` (from GitHub/DockerHub) and pass it inline. Override any hard-coded image tags with pinned versions for reproducibility.
|
||||
|
||||
### 11.5 "Compose app fails on second+ deploy — relation/table does not exist"
|
||||
|
||||
Classic stale volume problem. Sequence of events:
|
||||
1. First deploy: Postgres starts and auto-creates an empty `default` database (from `POSTGRES_DB` env var)
|
||||
2. App server starts, tries to `CREATE DATABASE` or `DROP DATABASE` inside a transaction → Postgres rejects it
|
||||
3. Deploy fails, containers stop — but the volume persists with the half-initialized DB
|
||||
4. Second deploy: Postgres finds existing data, skips init — but schema is corrupt/incomplete
|
||||
5. Server errors cascade forever
|
||||
|
||||
**Fix:**
|
||||
|
||||
```json
|
||||
// Step 1: find the volume
|
||||
{ "action": "apps.volumes.list", "params": { "uuid": "<app-uuid>" } }
|
||||
// → { "volumes": [{ "name": "abc123_db-data", "sizeBytes": 8192 }] }
|
||||
|
||||
// Step 2: wipe it
|
||||
{ "action": "apps.volumes.wipe", "params": { "uuid": "<app-uuid>", "volume": "abc123_db-data", "confirm": "abc123_db-data" } }
|
||||
|
||||
// Step 3: redeploy clean
|
||||
{ "action": "apps.deploy", "params": { "uuid": "<app-uuid>" } }
|
||||
```
|
||||
|
||||
If Postgres still auto-creates the database before the app server runs migrations, use `apps.exec` to drop it outside a transaction:
|
||||
|
||||
```json
|
||||
{ "action": "apps.exec", "params": { "uuid": "<app-uuid>", "service": "db", "command": "psql -U postgres -c 'DROP DATABASE IF EXISTS \"default\";'" } }
|
||||
```
|
||||
|
||||
Then redeploy.
|
||||
|
||||
### 11.7 "Healthcheck times out on first deploy"
|
||||
|
||||
Docker Compose healthchecks have a `start_period` grace window. Apps
|
||||
that run long-running migrations on first boot (Twenty, Directus,
|
||||
@@ -667,7 +715,7 @@ start, typically 120–600s.
|
||||
- Alternatively, handle migrations out-of-band via `apps.exec` and let
|
||||
the default healthcheck succeed instantly.
|
||||
|
||||
### 11.5 "I can't tell what's inside the container"
|
||||
### 11.8 "I can't tell what's inside the container"
|
||||
|
||||
`apps.exec` is the escape hatch. Useful shell one-liners:
|
||||
|
||||
@@ -685,7 +733,7 @@ Output is capped at 1 MB by default (bump with `max_bytes`). Commands
|
||||
that could exceed the wall-clock timeout should bump `timeout_ms`
|
||||
(max 600000 = 10 minutes).
|
||||
|
||||
### 11.6 "The agent wants to run something interactively"
|
||||
### 11.9 "The agent wants to run something interactively"
|
||||
|
||||
It can't. `apps.exec` is strictly non-interactive: no TTY, no stdin,
|
||||
no session resumption. For migrations and CLI invocations this is the
|
||||
|
||||
Submodule vibn-frontend updated: 8c83f8c490...6d71c63053
Reference in New Issue
Block a user