Skip to content

feat(skills): document webflow apps commands - #37

Merged
agustinchiarotto merged 6 commits into
mainfrom
feat/document-webflow-apps-commands
Aug 31, 2026
Merged

agustinchiarotto merged 6 commits into
mainfrom
feat/document-webflow-apps-commands

Conversation

@agustinchiarotto

@agustinchiarotto agustinchiarotto commented Jul 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Documents the webflow apps namespace in the Webflow Cloud CLI skill (plugins/webflow-skills/skills/webflow-cloud-command/SKILL.md) as beta, and refreshes stale cloud-namespace content. Command surface mirrors apps.ts / registerAppCommands.ts on webflow-cli main.

This PR now describes apps as @next-only rather than as GA. A follow-up PR will flip the framing to stable once the namespace is promoted — see Follow-up below. This reverses the earlier direction on this PR; details in the approach-change comment.

Beta framing

  • Beta banner at the top: the whole apps namespace ships only on @webflow/webflow-cli@next; on @latest it doesn't exist and every invocation fails as an unknown command. Includes how to tell the channels apart (a beta install carries a -next. version suffix — there is no public channel flag; __internal-build-channel is hidden and explicitly not public surface).
  • Install instructions switched to @next, with a note that @latest suffices for cloud init / cloud deploy alone.
  • Namespaces table reframed: apps = canonical but beta, cloud = what stable users have today. Records that the cloud init / cloud deploy deprecation notice fires only on beta builds — the CLI never advertises a namespace the user doesn't have.
  • > Beta — @next only callout on the whole "Managing apps" section.
  • New "Beta gating tiers" table separating the two independent gates (see Follow-up).

Commands added since the first draft

apps init --import (repo intake, incl. the --site-id xor --new rule, --mount conditionality, --branch / --idempotency-key / --skip-clone, and the flag-compatibility refusals), apps link, apps environments create / update / delete, apps deployments redeploy / trigger, and apps update --github-source.

Also documents the list filters (--site / --name / --branch / --key / --q, deployments list --status) with their AND-combined / empty-page-≠-absence semantics, and apps domains pagination.

Corrections to the earlier draft

  • deployments get has --wait (with --interval, floored 5s, and --timeout, capped 30min; exits 0/1 on terminal status). The draft said there was no --watch and gave a manual polling recipe in three places.
  • apps logs build requires a deployment ID. The draft said it defaults to the latest deployment; it fails fast, before authenticating, with missingFlag: "depId". The draft's example would have errored.
  • --dry-run support list was missing seven commands.
  • GitHub Actions example installed @latest but invoked webflow apps deploy — it would have failed with an unknown-command error.
  • Adopted @jallegretti-webflow's frontmatter description rewrite.
  • Dropped a CLD-* reference from a section heading — a ticket ID carries no meaning for an agent reading the skill.

Follow-up

The apps commands sit behind two independent gates, and the GA PR needs to account for both:

Tier Commands Reaches stable when
Namespace gate (if (isBetaBuild()) initApps(program) in cli/webflow.ts) init (incl. --import), deploy, list, get, domains, environments list, deployments list / get / redeploy / trigger, logs build / runtime, env-vars ×4 The namespace is promoted.
Second gate (inner isBetaBuild() in apps.ts) link, update, delete, environments create / update / delete Separately promoted. Removing the namespace gate alone does not ship these.

This PR no longer blocks on the gate removal — it's accurate as written for today's @next.

Test plan

  • CI structural checks pass (frontmatter name: / description: present)
  • Re-review of the beta framing (reverses the basis of the earlier approval)
  • Cross-read against feat(skills): Add Cloud apps skill #44 for consistency on CLI-side claims

Notes for reviewers

  • File is 1318 lines, over the 500-line CONTRIBUTING guideline. Kept single-file deliberately: four skills in this repo already exceed 1000 lines (cms-best-practices is 2110), and a split would churn the whole diff on an already-reviewed PR. Worth doing as its own PR if we want to start enforcing the limit.
  • Env var for the environment ID is WEBFLOW_APP_ENVIRONMENT_ID (the actual name in resolveResourceId.ts).
  • cloud list is documented as the scaffold-template lister (distinct from apps list), since create / list remain cloud-only.

agustinchiarotto and others added 2 commits July 14, 2026 18:01
Document the canonical `webflow apps` namespace in the Webflow Cloud skill
and refresh stale `cloud`-namespace content.

- Add a "Managing apps" section covering apps list/get/domains, environments
  list, deployments list/get (with the status enum + polling note),
  logs build/runtime, env-vars list/set/delete/import, and update/delete —
  each with a --json example, --fields defaults, the appId/envId resolver
  precedence, and the --no-input missingFlag contract. Read commands derive
  the workspace server-side (no --workspace-id).
- Present `apps init`/`apps deploy` and `--app-name`/`--app-id` as canonical;
  mark `cloud init`/`deploy`/`create` and `--project-name`/`--project-id` as
  deprecated aliases.
- Switch detection/config to `cloud.app_id` (legacy `cloud.project_id` still
  read as a fallback) and document env vars + the CLD-1960 resolver.
- Correct the scaffold ref note (Astro v2 + astro7 betaRef, Next.js v1).

Co-authored-by: Cursor <cursoragent@cursor.com>
- Simplify the scaffold-fetch note to avoid exposing internal versioning/beta
  roadmap details publicly.
- Remove the "standalone" wording in favor of the existing "project app" term.

Co-authored-by: Cursor <cursoragent@cursor.com>

@jallegretti-webflow jallegretti-webflow left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, all mentions of standalone, beta and @next are removed as this will be released once CLI hits GA 👍

---
name: webflow-cli:cloud
description: Initialize, build, and deploy full-stack Webflow applications to Webflow Cloud hosting. Supports site-attached deploys (linked to an existing Webflow site) and project app deploys (independent project, no existing site required). Use when creating new projects, deploying existing ones, or setting up CI/CD pipelines for Webflow Cloud.
description: Manage full-stack Webflow Cloud apps from the CLI. Initialize, build, and deploy apps (site-attached or project apps), and manage existing apps — list/get apps, view domains and live URLs, inspect environments and deployments, read build and runtime logs, and manage environment variables. Use when creating, deploying, inspecting, or operating Webflow Cloud apps, listing apps, checking deployment status, reading logs, managing env vars, or setting up CI/CD pipelines.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is NIT-picking from my side but it has several repeated connectors. Can we give it another pass on claude/codex to improve the wording ?

ie draft:
description: Create, build, and deploy Webflow Cloud apps from the CLI (site-attached or project apps), and manage existing ones — apps, domains, environments, deployments, build/runtime logs, and environment variables including secrets. Use when initializing or deploying a Cloud app, setting up CI/CD (GitHub Actions or GitHub-linked deploys), setting or importing secrets, retrying or rolling back a deployment, diagnosing a failed build, or resolving app/environment/workspace IDs from webflow.json or env vars.

The `apps` namespace ships only on the CLI's `@next` channel, so document
it as beta throughout rather than as generally available. A follow-up PR
will flip this once the namespace is promoted to stable.

- Add a beta banner, `@next` install instructions, and a gating-tiers table
  separating the namespace gate from the second gate that independently
  holds back link/update/delete and environments create/update/delete.
- Document commands added since the first draft: `apps init --import`
  (repo intake), `apps link`, `apps environments create/update/delete`,
  `apps deployments redeploy/trigger`, and `apps update --github-source`.
- Document the list filters (`--site`/`--name`/`--branch`/`--key`/`--q`,
  `deployments list --status`) and their AND/empty-page semantics, plus
  `apps domains` pagination.
- Correct three stale claims: `deployments get` now has `--wait`
  (`--interval`/`--timeout`), `logs build` requires a deployment ID rather
  than defaulting to the latest, and the `--dry-run` support list was
  missing seven commands.
- Fix the GitHub Actions example, which installed `@latest` but invoked
  `webflow apps deploy`.
- Adopt the reviewer's frontmatter description rewrite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@agustinchiarotto

Copy link
Copy Markdown
Contributor Author

Refreshed this against webflow-cli main and changed the approach: everything is now documented as beta (@next) rather than as GA.

@jallegretti-webflow flagging directly, since this reverses the basis of your approval ("all mentions of standalone, beta and @next are removed as this will be released once CLI hits GA"). Re-review needed.

Why the change: rather than hold the PR until the beta gate is removed, we're documenting the current @next reality now and landing a follow-up PR to flip the framing to stable at GA. That unblocks this one, and it means the skill stops being wrong for the people actually on @next today.

Why it needed a refresh regardless: the previous commit was from 2026-07-15 and the CLI moved a lot since. Eight commands were missing entirely (apps init --import, link, environments create/update/delete, deployments redeploy/trigger, update --github-source), and three documented claims had gone stale — most notably deployments get --wait now exists (the doc said to poll manually, in three places) and apps logs build requires a deployment ID rather than defaulting to the latest, so the example as written would have errored. Full breakdown in the updated description.

Two things worth a look during review:

  1. The gating-tiers table. link, update, delete, and environments create/update/delete sit behind a second, independent isBetaBuild() inside apps.ts that the namespace-gate removal doesn't touch. The GA follow-up has to promote those separately or keep them marked beta — flagging so it doesn't get missed.
  2. Line count: 1318, over the 500-line CONTRIBUTING guideline. Kept single-file on purpose (four skills here already exceed 1000; cms-best-practices is 2110). Happy to split into references/ as its own PR if we'd rather start enforcing that.

@nbverboven-webflow — #44 adds an MCP-side cloud-apps skill that delegates creation, local builds/deploys, and env-var writes to the CLI. No file conflict with this PR, but the CLI-side claims in both should agree. Worth a cross-read before either merges, particularly on the --wait / redeploy / trigger behaviour, which changed since this PR was first written.

@agustinchiarotto
agustinchiarotto marked this pull request as ready for review August 29, 2026 15:05
agustinchiarotto and others added 2 commits August 29, 2026 12:17
Path A only branched on "existing code" vs "empty directory", so a repo
already on GitHub was always routed to a local `apps deploy` — producing an
app that is not GitHub-connected, and that `deployments trigger`/`redeploy`
and dashboard push-to-deploy all refuse. `apps init --import` was documented
only as reference material further down, so an agent following the tree
never reached it.

- Add Path A3 (existing GitHub repository → GitHub-connected app) with
  site-attached / project-app / CI variants, the GitHub App prerequisite,
  and the `deployments trigger` follow-up instead of `apps deploy`.
- Add the second routing question and an A1 → A3 pointer, and note the
  `apps update --github-source` recovery for an app created the A1 way.
- Add both `--import` forms to the non-TTY required-flag table.

Also close three completeness gaps:

- `--dry-run` works on the scaffold `apps init`, not just `--import`.
- `missingFlag` carries two shapes (bare key from resolvers, flag spelling
  from `apps init` compatibility refusals) — say so, and note it names the
  flag to drop for mutually-exclusive pairs.
- `mount` is absent from the `environments list` table default; document
  the full field set and how to request it.

Fix two pre-existing broken intra-doc anchors.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The channel-detection examples cited 1.14.0-next.3 / 1.13.1, a major
behind the published tags (next 2.8.0-next.0, latest 2.7.0). Update both
and say explicitly that the check is the `-next.` suffix, not the numbers,
so the example going stale again does not make the guidance wrong.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@nbverboven-webflow

nbverboven-webflow commented Aug 30, 2026 •

Copy link
Copy Markdown
Contributor

@nbverboven-webflow — #44 adds an MCP-side cloud-apps skill that delegates creation, local builds/deploys, and env-var writes to the CLI. No file conflict with this PR, but the CLI-side claims in both should agree. Worth a cross-read before either merges, particularly on the --wait / redeploy / trigger behaviour, which changed since this PR was first written.

The MCP skill only references this one, never specific commands. It does so as

"use the webflow-cli:cloud skill when the task requires <something not supported by the MCP tool>"

so there's no drift to worry about.

@jallegretti-webflow jallegretti-webflow left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (blocking): The apps deploy preflight identity-resolution table has the wrong precedence order and is missing a row.

Actual order per apps/webflow-cli/src/cloud/preflight.ts:67-104: --site-id flag → --workspace-id flag → WEBFLOW_SITE_ID env → manifest.siteId → WEBFLOW_WORKSPACE_ID env → manifest.cloud.workspace_id → (hard error under --no-input, else picker). The doc has manifest values resolving before any env var, and omits WEBFLOW_WORKSPACE_ID from the table entirely. Env vars actually win over the manifest for both site and workspace.


issue (non-blocking): The apps deploy flags table says --mount is "Always required with --no-input," but it isn't — it silently falls back to a /app default instead of erroring.

deployCloudHandler.ts only hard-throws under no-input for the app-name/app-id resolution; --mount goes through input() in inquirer-wrapper.ts:287-301, which under isNoInput() just returns its default ("/app") rather than throwing. Worth calling out explicitly, since the doc elsewhere warns that assuming a default mount causes ENVIRONMENT_MOUNT_MISMATCH — the real risk here is a silent wrong deploy, not the hard failure the flag table implies.

@jallegretti-webflow

Copy link
Copy Markdown
Contributor

Correction to my earlier review comment: I said the silent --mount fallback under --no-input on apps deploy is /app. That's wrong — traced it further:

deployCloudHandler.ts:315-320 prompts with default: "/app" but passes no validate function. Under --no-input, inquirer-wrapper.ts:287-297's no-input branch does if (validateResult !== true) return null; — since validate is absent, options.validate?.(options.default) is undefined, which is !== true, so it returns null, not the default. That null then goes through normalizeMountPath(null), which treats falsy input as "/" (root) and returns that.

So the real silent fallback is root (/), not /app. The rest of the original finding stands — it's still not "Always required" as the flags table claims, and it's still a silent-wrong-mount risk rather than a hard failure.

… claim

Addresses review feedback on the apps deploy section.

The preflight identity table had env vars resolving after the manifest.
`resolveIdentity` in cloud/preflight.ts uses the shared resolver, whose
order is flag > env var > manifest, and `WEBFLOW_WORKSPACE_ID` was missing
from the table entirely. Reorder, add the missing row, and note the
short-circuit: any resolved site wins before workspace resolution is
attempted, so a stale WEBFLOW_SITE_ID silently overrides a manifest set up
for a project-app deploy.

The flags table also called `--mount` "always required with --no-input". It
is not enforced. The mount prompt supplies a `/app` default but no
validator; the no-input branch of `input()` only returns a default that
validates, so it returns null, which `normalizeMountPath` turns into `/`.
Root is a valid mount, so the deploy silently lands there. Document it as a
wrong-deploy risk rather than a hard failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@agustinchiarotto

Copy link
Copy Markdown
Contributor Author

Both findings verified against main and fixed in 7082bb6. Thanks — the blocking one was a real inversion, not a wording slip.

Blocking — precedence order. Confirmed exactly as you described. resolveIdentity (cloud/preflight.ts:67-104) delegates to resolveResourceId, whose documented order is explicit flag > env var > webflow.json > prompt > error — so env beats manifest, and the table had it backwards. WEBFLOW_WORKSPACE_ID was missing too. Table reordered to flag → flag → WEBFLOW_SITE_ID → manifest.siteId → WEBFLOW_WORKSPACE_ID → manifest.cloud.workspace_id → error/picker.

I also added the consequence that follows from the same code and wasn't called out: resolveIdentity returns as soon as any site resolves, before workspace resolution is attempted. So a stale exported WEBFLOW_SITE_ID doesn't just outrank manifest.siteId — it silently beats a manifest configured for a project-app deploy and turns it into a site-attached one. That seemed worth stating explicitly given the failure is invisible.

Non-blocking — --mount. Your correction is right, and I traced the same path to confirm it end to end:

  • deployCloudHandler.ts:315-320 calls input({ message, default: "/app" }) with no validate.
  • inquirer-wrapper.ts:288-294, no-input branch: const validateResult = await options.validate?.(options.default) → undefined; if (validateResult !== true) return null. So it returns null, not /app.
  • normalizeMountPath(null) → if (!mountPath) return "/".
  • isValidMountPath("/") → true (non-empty, starts with /, no ..), so nothing rejects it downstream.

Net: silent deploy at root, no error and no warning. Flags table no longer says "always required"; it now says to always pass it while stating plainly that it isn't enforced, with a warning giving the mechanism and tying it to the ENVIRONMENT_MOUNT_MISMATCH that surfaces later.

Worth noting this is arguably a CLI bug rather than a docs bug — a prompt default that silently becomes something other than the default under --no-input is surprising, and adding a validate to that one prompt would make /app actually apply. Happy to file it if you agree; documenting it here either way.

The same --mount correction is now in the docs PR (webflow/openapi-internal#936), which carried the identical "always required" claim.

@nbverboven-webflow — understood on #44, thanks for checking. Generic reference means no drift risk; dropping that concern.

@agustinchiarotto
agustinchiarotto merged commit c684336 into main Aug 31, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants