Extend docs-publisher to publish to GitLab Pages and Cloudflare Pages alongside GitHub Pages — one docs-init run detects the git host and drops in the right deploy pipeline, while the host-agnostic build scripts stay completely untouched.
Read and implement all steps in the plan at docs/plans/add-multi-host-deploy-targets.html — Add GitLab Pages and Cloudflare Pages deploy targets to docs-publisher
Run as workflow — launch parallel subagents
Run a workflow to implement the plan at docs/plans/add-multi-host-deploy-targets.html — Add GitLab Pages and Cloudflare Pages deploy targets to docs-publisher
add-multi-host-deploy-targets.html
docs/plans/add-multi-host-deploy-targets.html
Context
The docs-publisher plugin (planned in docs/plans/create-docs-publishing-skills.html, still status: todo) packages the agentics docs pipeline as installable skills: a docs-init command scaffolds docs/, copies build scripts into the user's project, and drops a GitHub Actions deploy workflow into .github/workflows/. Today that deploy stage is GitHub-only.
This plan is the verbatim "GitLab Pages and Cloudflare Pages support" Wish List item from that parent plan, promoted to a real feature. It adds two more deploy targets without touching the build scripts — those already emit static HTML into docs/ and are host-agnostic. Only the deploy wrapper changes per host: GitHub Pages uploads a docs/ artifact via Actions, GitLab Pages publishes a public/ artifact from a pages CI job, and Cloudflare Pages either connects the repo through the dashboard or runs wrangler pages deploy in CI.
Dependency: this plan layers onto the docs-publisher plugin skeleton, docs-init, and docs-publish. If the parent plan has not been implemented yet, implement it first — the steps below modify files that parent plan creates.
Resolved decisions: (1) Cloudflare ships both mechanisms — a wrangler.toml for dashboard Git-integration and an optional deploy-cloudflare.yml CI workflow — and docs-init asks the user which to use. (2) docs-publish becomes host-aware so it reports the correct published URL (github.io / gitlab.io / pages.dev) per target.
Files to Modify
- kit/plugins/docs-publisher/reference/
.gitlab-ci.ymlnew GitLab Pages deploy jobdeploy-cloudflare.ymlnew Cloudflare CI deploy workflowwrangler.tomlnew Cloudflare Pages config- kit/plugins/docs-publisher/commands/
docs-init.mdmodified host detection + template copydocs-publish.mdmodified host-aware published URL- kit/plugins/docs-publisher/
README.mdmodified document three deploy targetsCHANGELOG.mdmodified multi-host feature entrykit/plugins/docs-publisher/scripts/detect-host.shnew shared git-host classifier.claude-plugin/marketplace.jsonmodified minor version bumptests/pages/deploy-templates.test.shnew template validity smoke testtests/pages/detect-host.test.shnew host-detection unit testtests/pages/docs-init-host-copy.test.shnew copy-mapping integration test
Diagram
git remote get-url origingithub | gitlab | otherother → ask: Cloudflare CI vs dashboardidempotent file copypush → Pages build| Host | Detection signal | Deploy template | Copied to | Published URL |
|---|---|---|---|---|
| GitHub Pages | github.com in remote |
deploy-pages.yml |
.github/workflows/ |
<owner>.github.io/<repo> |
| GitLab Pages | gitlab.com in remote |
.gitlab-ci.yml |
repo root | <owner>.gitlab.io/<repo> |
| Cloudflare (dashboard) | prompt (no github/gitlab match) | wrangler.toml |
repo root | <project>.pages.dev |
| Cloudflare (CI) | prompt (no github/gitlab match) | wrangler.toml + deploy-cloudflare.yml |
root + .github/workflows/ |
<project>.pages.dev |
Steps
reference/.gitlab-ci.yml
pages CI job leaves in public/. The build scripts already emit static HTML into docs/, so the template only needs a pages job that copies docs/ → public/ and declares public as its artifact path, scoped to the default branch.Verify
kit/plugins/docs-publisher/reference/.gitlab-ci.yml. Confirm it (1) defines a pages job, (2) runs cp -r docs public (or rsync) in its script, (3) sets artifacts: paths: [public], and (4) restricts to the default branch via rules or only. Validate it parses: python3 -c "import yaml,sys; yaml.safe_load(open('kit/plugins/docs-publisher/reference/.gitlab-ci.yml'))" exits 0.reference/wrangler.toml and reference/deploy-cloudflare.yml
wrangler.toml alone only configures a Pages project — it does not deploy. Shipping both a wrangler.toml (with pages_build_output_dir = "docs", for the dashboard Git-integration path) and a deploy-cloudflare.yml workflow (running wrangler pages deploy docs, for the fully-automated path) lets docs-init offer the user either route.Verify
reference/wrangler.toml contains pages_build_output_dir = "docs" and a name placeholder. Confirm reference/deploy-cloudflare.yml runs wrangler pages deploy docs (e.g. via cloudflare/wrangler-action) and references ${{ secrets.CLOUDFLARE_API_TOKEN }} and ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} — never hard-coded credentials. Parse checks: python3 -c "import tomllib;tomllib.load(open('.../wrangler.toml','rb'))" and a yaml.safe_load on the workflow both exit 0.scripts/detect-host.sh
docs-init and docs-publish need the same github/gitlab/other decision. Extracting one small, testable shell helper avoids duplicating fragile URL-parsing prose across two markdown command files and gives the unit test a real target. It is copied into the user's project by docs-init alongside the other build scripts.Verify
kit/plugins/docs-publisher/scripts/detect-host.sh. Confirm it defines a detect_host() function (or accepts a remote URL arg) that prints github for a URL containing github.com, gitlab for gitlab.com, and other for anything else (including an empty/missing remote). Confirm it handles both https:// and git@ SSH forms and is POSIX-sh / bash compatible (runs on macOS and Linux).docs-init
detect-host.sh, copy the matching template to the right location, and — for the non-github/gitlab case — ask via AskUserQuestion whether the user wants the Cloudflare CI workflow or the dashboard route, copying deploy-cloudflare.yml only for the CI choice. All copies must be idempotent.Verify
kit/plugins/docs-publisher/commands/docs-init.md. Confirm the body: (1) calls detect-host.sh on origin; (2) for github copies deploy-pages.yml → .github/workflows/; (3) for gitlab copies .gitlab-ci.yml → repo root; (4) for other uses AskUserQuestion to choose Cloudflare CI vs dashboard, copying wrangler.toml → root in both cases and deploy-cloudflare.yml → .github/workflows/ only for CI; (5) never overwrites an existing deploy file without explicit user confirmation. Confirm detect-host.sh is added to the list of scripts docs-init copies into the project.docs-publish host-aware when reporting the published URL
docs-publish currently reports a GitHub Pages URL. Publishing to GitLab or Cloudflare should report the correct destination, not a misleading github.io link. Reusing detect-host.sh keeps the classification identical to what docs-init used.Verify
kit/plugins/docs-publisher/commands/docs-publish.md. Confirm it derives the published URL per host: github → https://<owner>.github.io/<repo>/, gitlab → https://<owner>.gitlab.io/<repo>/, Cloudflare → https://<project>.pages.dev (project name read from wrangler.toml when present, else noted as dashboard-defined). Confirm the existing --dry-run behaviour is preserved.version bump plus a CHANGELOG entry for any plugin change, and users need docs explaining the three deploy targets and how docs-init picks one. Adding deploy targets is a new feature → a MINOR bump.Verify
kit/plugins/docs-publisher/README.md has a "Deploy targets" section listing GitHub / GitLab / Cloudflare and describing host auto-detection. Confirm kit/plugins/docs-publisher/CHANGELOG.md has a new entry. Confirm the docs-publisher version in .claude-plugin/marketplace.json is bumped one MINOR above its main value, and that python3 -m json.tool .claude-plugin/marketplace.json exits 0.Tests
File: tests/pages/deploy-templates.test.sh
Type: smoke test
Asserts: the plan's objective — that docs-publisher gained GitLab + Cloudflare deploy support. Validates that reference/.gitlab-ci.yml and reference/deploy-cloudflare.yml parse as YAML and reference/wrangler.toml parses as TOML; that .gitlab-ci.yml contains a pages job publishing public; that deploy-cloudflare.yml invokes wrangler pages deploy and references the two secrets (never literal tokens); and that wrangler.toml sets pages_build_output_dir = "docs".
Run: bash tests/pages/deploy-templates.test.sh
File: tests/pages/detect-host.test.sh
Targets: detect_host() in kit/plugins/docs-publisher/scripts/detect-host.sh
Key cases: https://github.com/o/r.git → github; git@github.com:o/r.git → github; https://gitlab.com/o/r → gitlab; a self-hosted/unknown host → other; empty/missing remote → other.
File: tests/pages/docs-init-host-copy.test.sh
Targets: the docs-init host-detection + copy logic exercised against temp git repos
Key cases: a temp repo with a github.com remote yields .github/workflows/deploy-pages.yml; a gitlab.com remote yields a root .gitlab-ci.yml; the Cloudflare-CI path yields both wrangler.toml and deploy-cloudflare.yml while the dashboard path yields only wrangler.toml; a second run does not overwrite an edited deploy file.
Acceptance Criteria
Verification
Run bash tests/pages/deploy-templates.test.sh and bash tests/pages/detect-host.test.sh — both exit 0. Then create three throwaway git repos and set their origin remotes to a github.com, a gitlab.com, and a self-hosted URL respectively; run the docs-init copy logic (via tests/pages/docs-init-host-copy.test.sh) and confirm each repo receives only its host's template in the right place, that the Cloudflare prompt branches correctly between the CI and dashboard file sets, and that a second run leaves an edited deploy file untouched. Finally, run docs-publish --dry-run in each repo and confirm the reported published URL matches the host (github.io / gitlab.io / pages.dev). Confirm python3 -m json.tool .claude-plugin/marketplace.json succeeds and the docs-publisher version is higher than on main.
Completion Checklist
Completion Report
No items to report — all requirements met.
Unresolved Questions
-
Where should the Cloudflare Pages project name come from?
For docs-publisher's Cloudflare support, decide the source of truth for the Pages project name used in wrangler.toml and in docs-publish's reported pages.dev URL. Options: (a) derive it from the repo basename, (b) prompt the user during docs-init, (c) read it back from an existing wrangler.toml. Recommend one default with reasoning, accounting for the fact that the dashboard route may have created a project under a different name than the repo. If prompting is chosen, specify exactly when docs-init asks and how docs-publish recovers the value later.