From 31d89ee0ae140b7563a19a91edd96ee7bea5cd53 Mon Sep 17 00:00:00 2001 From: Peter Amiri Date: Wed, 6 May 2026 09:02:25 -0700 Subject: [PATCH 1/2] docs: switch Social 4 links to canonical blog.wheels.dev / guides.wheels.dev MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All 11 GitHub-blob source links across the four channels (Slack, LinkedIn, X reply 3, GitHub Discussions) replaced with their guides.wheels.dev equivalents — readers now land on the styled docs instead of raw MDX. Each canonical URL verified to return HTTP 200. Also adds a canonical blog-post URL prominent in each channel: - Slack: prepended `<...|Read the full post>` to the deployment-guide line - LinkedIn: new "Read the full post:" line above the docs links - X reply 3: swapped the deployment-guide link for the canonical blog URL - Discussions: blockquote callout below the lead paragraph linking to the post Third-party links left alone: kamal-deploy.org and basecamp/kamal-proxy on GitHub remain (correct destinations for the upstream Kamal references). Net: 11 GH-blob URLs removed, 11 canonical-guides URLs added, 4 blog-canonical URLs added across the four channels. --- .../blog-skeletons/social-announcements.md | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/docs/releases/blog-skeletons/social-announcements.md b/docs/releases/blog-skeletons/social-announcements.md index a563d72f8..540fe6722 100644 --- a/docs/releases/blog-skeletons/social-announcements.md +++ b/docs/releases/blog-skeletons/social-announcements.md @@ -389,7 +389,7 @@ Wheels 4.0 brings a new command: `wheels deploy`. It's a port of Basecamp's Kamal into the Wheels CLI — zero-downtime Dockerized deploys to Linux servers over plain SSH. No Ruby runtime, no gem install, no second tool to learn. - + · What you get: • One command from laptop to production: `wheels deploy` @@ -420,8 +420,9 @@ What `wheels deploy` is not: it is not a Kubernetes integration, not a systemd-n If you're shipping a Dockerized Wheels app to one or more Linux hosts and you want zero-downtime rollover out of the box, this is the shortest path in 4.0. -Guide: https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/index.mdx -Migrating from Kamal: https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/migrating-from-kamal.mdx +Read the full post: https://blog.wheels.dev/posts/wheels-deploy-kamal-port/ +Deployment guide: https://guides.wheels.dev/v4-0-0-snapshot/deployment/ +Migrating from Kamal: https://guides.wheels.dev/v4-0-0-snapshot/deployment/migrating-from-kamal/ #CFML #Wheels #Kamal #DevOps #Deployment #OpenSource ``` @@ -469,8 +470,8 @@ No new syntax. Just ERB out — `${VAR}` is something Kamal already supports too Secret adapters: 1Password, Bitwarden, AWS, LastPass, Doppler. -Guide: -https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/index.mdx +Full post: +https://blog.wheels.dev/posts/wheels-deploy-kamal-port/ ``` ### GitHub Discussions @@ -480,6 +481,8 @@ https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/d ```markdown Wheels 4.0 introduces a new built-in command: `wheels deploy`. It is a port of [Basecamp's Kamal](https://kamal-deploy.org/) — the container-based deployer — into the Wheels CLI. This post is for anyone currently running ad-hoc deploy scripts (or running Ruby Kamal alongside Wheels) who wants to understand what's shipping and what the contract is. +> **Full blog post:** https://blog.wheels.dev/posts/wheels-deploy-kamal-port/ + ## Why a port, not a plugin Wheels ships as a LuCLI binary (CFML + Java). Asking users to `gem install kamal` adds a Ruby runtime dependency and a second CLI to learn. Kamal's proxy component ([kamal-proxy](https://github.com/basecamp/kamal-proxy)) is already a standalone Go binary — what's Ruby-specific is only the developer-side orchestrator that opens SSH connections, uploads config, and runs `docker` commands. So we ported the orchestrator, left `kamal-proxy` untouched, and kept the on-server state byte-compatible. @@ -549,10 +552,10 @@ Every verb supports `--dry-run` — prints the exact shell commands that would r ## Docs -- [Deployment landing page](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/index.mdx) — start here for context and when-to-use guidance -- [Your first deploy](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/first-deploy.mdx) — hands-on walkthrough -- [Migrating from Kamal](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/migrating-from-kamal.mdx) — the full compatibility contract and switch-over checklist -- [Config reference](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/config-reference.mdx), [secrets](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/secrets.mdx), [hooks](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/hooks.mdx), [accessories](https://github.com/wheels-dev/wheels/blob/develop/web/sites/guides/src/content/docs/v4-0-0-snapshot/deployment/accessories.mdx) +- [Deployment landing page](https://guides.wheels.dev/v4-0-0-snapshot/deployment/) — start here for context and when-to-use guidance +- [Your first deploy](https://guides.wheels.dev/v4-0-0-snapshot/deployment/first-deploy/) — hands-on walkthrough +- [Migrating from Kamal](https://guides.wheels.dev/v4-0-0-snapshot/deployment/migrating-from-kamal/) — the full compatibility contract and switch-over checklist +- [Config reference](https://guides.wheels.dev/v4-0-0-snapshot/deployment/config-reference/), [secrets](https://guides.wheels.dev/v4-0-0-snapshot/deployment/secrets/), [hooks](https://guides.wheels.dev/v4-0-0-snapshot/deployment/hooks/), [accessories](https://guides.wheels.dev/v4-0-0-snapshot/deployment/accessories/) ## Question for the thread From 2178c7d9205ef3e387aeada0aaa44e9da957c98d Mon Sep 17 00:00:00 2001 From: Peter Amiri Date: Wed, 6 May 2026 09:02:25 -0700 Subject: [PATCH 2/2] docs: strip duplicate H1 + byline + divider from why-we-rebuilt post MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The post's body opened with `# Why We Rebuilt Our CI Pipeline From 40 Minutes to 82 Seconds` followed by `_April 9, 2026 — Peter Amiri, Wheels Core Team_` and a `---` divider — all of which PostLayout.astro already renders from frontmatter (title, author, date). Result was two

elements on the live page, same pattern that bit Blog 09 in #2435. Body now starts directly with the lead paragraph ("For years, the Wheels CI pipeline ran every commit through a gauntlet..."). The "82 seconds" substance is preserved in the next paragraph. Spotted via a corpus-wide sweep: 150 tracked posts scanned, 140 already clean, 9 use H1 as section markers (correctly skipped), and only this one + Blog 09 had the duplicate-title pattern. Tracked broader cleanup + enforcement as #2436. Note: the body's longer subtitle ("From 40 Minutes to 82 Seconds") is lost as a heading — but it remains in the lead paragraph as the "82 seconds" claim, so the rhetorical hook is preserved. --- web/content/blog/posts/why-we-rebuilt-our-ci-pipeline.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/web/content/blog/posts/why-we-rebuilt-our-ci-pipeline.md b/web/content/blog/posts/why-we-rebuilt-our-ci-pipeline.md index 102b2b79e..ffb473ecd 100644 --- a/web/content/blog/posts/why-we-rebuilt-our-ci-pipeline.md +++ b/web/content/blog/posts/why-we-rebuilt-our-ci-pipeline.md @@ -15,12 +15,6 @@ coverImage: null legacyId: '1165378763664687105' --- -# Why We Rebuilt Our CI Pipeline From 40 Minutes to 82 Seconds - -_April 9, 2026 — Peter Amiri, Wheels Core Team_ - ---- - For years, the Wheels CI pipeline ran every commit through a gauntlet: five CFML engines, seven databases, Docker Compose orchestrating it all. It was thorough. It was comprehensive. And it was killing our velocity. Today we shipped a fundamentally different approach. Our primary CI now runs in **82 seconds**. No Docker. No CommandBox. Just LuCLI, Lucee 7, and SQLite — the same tools a developer uses on their laptop.