From be34fe1d10edb4a013e934cbc51cf964f3321e55 Mon Sep 17 00:00:00 2001 From: Vishal Rana Date: Mon, 17 Aug 2026 09:54:25 -0700 Subject: [PATCH 1/2] fix(site): give the landing page a title, and a tagline that matches the repo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Starlight renders " ". Every page reads correctly under that rule — "Install · Onebox", "CLI commands · Onebox" — except the landing page, whose own title is the site title, so it came out as "Onebox · Onebox". astro.config.mjs already carried a note about this, saying titleDelimiter exists because the page otherwise "renders as Onebox | Onebox". That fixed the separator and not the duplication: a delimiter cannot know both halves are the same word. The note read as though the problem were solved, which is probably why it survived; it now says what the setting actually does, which is serve every other page. The wording is the three beats the repository already uses on itself. The GitHub description reads "plan-before-apply, zero-downtime deploys for one box"; as a single title that is 61 characters and long enough to be cut short in search results, so it is split into clauses rather than trimmed and every idea survives. index.html Onebox · Plan-before-apply deploys. Zero downtime. One box. start/install.html Install · Onebox reference/cli.html CLI commands · Onebox 404.html 404 · Onebox og:title is set alongside it. Starlight defaults that to the bare page title, so without it the link renders in Slack, X and LinkedIn as a card called "Onebox" — identified by its own name and nothing else, which is the problem this change exists to fix. Both tags are deduped by Starlight against its defaults rather than appended, verified in the built output: one , one og:title. Frontmatter is the mechanism because it is the one that works. Emitting a <title> from the Head component instead produces two title tags with Starlight's own — the wrong one — first; that was measured, not assumed. The `tagline` in astro.config.mjs is brought into step. It renders nowhere today: Starlight uses it for a splash hero, and index.mdx supplies its own. It is updated anyway, because the day a second splash page exists is not the day to discover the tagline drifted. No claim is made that 59 characters is safe from truncation. Search engines cut on rendered width, not a character count, and this string capitalises three words the original did not. It is shorter, which is the honest claim. `just check` passes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- site/astro.config.mjs | 15 ++++++++++++--- site/src/content/docs/index.mdx | 28 ++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/site/astro.config.mjs b/site/astro.config.mjs index 119dca39..5f923cb5 100644 --- a/site/astro.config.mjs +++ b/site/astro.config.mjs @@ -17,12 +17,21 @@ export default defineConfig({ integrations: [ starlight({ title: "Onebox", - // Without this the landing page, whose own title is also "Onebox", - // renders as "Onebox | Onebox". + // The separator between a page's title and the site's: "Install · Onebox". + // It was added for the landing page, which is titled "Onebox" like the + // site and so read as "Onebox | Onebox" — that it still read as + // "Onebox · Onebox" afterwards is the part the original note missed. The + // landing page now sets its own title outright and does not pass through + // here at all; every other page does, which is what this is for. titleDelimiter: "·", description: "Production operations for an application intentionally running on one server.", - tagline: "One application. One box. Evidence-backed operations.", + // The project tagline, in the same words as the GitHub description and the + // landing page's title. Starlight renders this only on a splash page that + // does not supply its own hero tagline; index.mdx supplies one, so today + // this has no output. It is kept in step anyway, because the day a second + // splash page exists is not the day to discover the tagline drifted. + tagline: "Plan-before-apply deploys. Zero downtime. One box.", social: [ { icon: "github", diff --git a/site/src/content/docs/index.mdx b/site/src/content/docs/index.mdx index 5584c86e..9f2643e4 100644 --- a/site/src/content/docs/index.mdx +++ b/site/src/content/docs/index.mdx @@ -3,6 +3,34 @@ title: Onebox description: Production operations for an application intentionally running on one server. summary: Landing page. What Onebox is, who it is for, and the fastest path into it. template: splash +# This page's own title is the site title, so Starlight's +# "<page title> <delimiter> <site title>" pattern rendered it as "Onebox · +# Onebox". titleDelimiter in astro.config.mjs chose the separator; it cannot +# know both halves are the same word. +# +# Overriding here is the mechanism that works. Emitting a <title> from the Head +# component instead produces two of them, with Starlight's own — the wrong one — +# first; that was measured, not assumed. Starlight dedupes a frontmatter `title` +# tag against its default, so this one replaces it rather than joining it. +# +# og:title is set too. Starlight defaults it to the bare page title, so without +# this the link renders in Slack, X and LinkedIn as a card called "Onebox" — +# identified by its own name and nothing else, which is the problem this block +# exists to fix. +# +# The wording is the three beats the repository already uses on itself: the +# GitHub description reads "plan-before-apply, zero-downtime deploys for one +# box". As one sentence that is 61 characters and long enough to be cut short in +# search results, so it is split into clauses rather than trimmed — every idea +# survives. Search engines cut on rendered width rather than a character count, +# so 59 is shorter, not guaranteed safe. +head: + - tag: title + content: "Onebox · Plan-before-apply deploys. Zero downtime. One box." + - tag: meta + attrs: + property: og:title + content: "Onebox · Plan-before-apply deploys. Zero downtime. One box." hero: tagline: | Production operations for an application intentionally running on one server. From 913c4aae5b83cdf2992639dd9b32a0b35b3f8a94 Mon Sep 17 00:00:00 2001 From: Vishal Rana <v@labstack.com> Date: Mon, 17 Aug 2026 10:49:58 -0700 Subject: [PATCH 2/2] docs: say "one server" in the two summaries that said otherwise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lines that introduce the product described its constraint with three different nouns. The CLI's one-line summary said "one host", docs/product.md's title said "one box", and the README, the site description, the CLI's own long help and llms.txt all said "one server". Nothing was wrong; they just did not agree, and these are the lines a reader meets first. The two outliers now say server as well. This is deliberately not a sweep. Body prose across the documentation still says "host" in about five places — "one host has one owner", "two Onebox applications on one host", "side by side on one host" — and it is right there, because those sentences are about the machine rather than about the product's scope. Renaming them would trade one inconsistency for a worse one. "Box" survives where it is the product's name rather than a noun: Onebox, and the tagline's closing beat "One box." No generated page moved. The CLI reference publishes the long help, which already said server; only the short summary changed, and that is not published. `just docs-generate` confirms it. `just check` passes, as do the cmd and app test suites. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --- cmd/ob/main.go | 2 +- docs/product.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/ob/main.go b/cmd/ob/main.go index c5907747..f1e4a8cd 100644 --- a/cmd/ob/main.go +++ b/cmd/ob/main.go @@ -37,7 +37,7 @@ func newRootCmd() *cobra.Command { g := &globalFlags{} root := &cobra.Command{ Use: "ob", - Short: "onebox — one application, one host", + Short: "onebox — one application, one server", Long: "onebox (ob) — plan-before-apply production operations for one application on one server.\n\nYou describe what the application is in ob.yml (or ob.yaml); Onebox generates\nthe Compose runtime, the names, the routing and the supporting services.\nAgentless over SSH, health-gated, journaled and fenced.", Version: version, SilenceUsage: true, diff --git a/docs/product.md b/docs/product.md index d01e297a..61b79465 100644 --- a/docs/product.md +++ b/docs/product.md @@ -1,4 +1,4 @@ -# Onebox — production operations for one application on one box +# Onebox — production operations for one application on one server > Status: product direction >