OG Images
How social share cards are generated with bin/rails og:images, and how to add your own.
The social share card that shows up when someone pastes a link into Slack, X, or iMessage is a
generated PNG, not a hand-drawn image. bin/rails og:images builds one per coding-agent landing
page, and bin/rails og:images:docs builds one per docs category and page, including the one this
guide is talking about right now.
How it works
Each task renders an ERB template to a local HTML file, using the site's own design tokens copied
inline (Propshaft-bundled CSS isn't sized for a 1200x630 card, so the template carries its own
copy of the relevant :root variables), then screenshots that file with headless Chrome at 2x
device-scale-factor, landing on a 2400x1260 PNG. A browser renders the card rather than an SVG
rasterizer, because the card is the Terminal design system at a larger size, and the only
renderer that draws oklch() colors and loads IBM Plex the way the live site does is the engine
the live site runs in.
This needs Chrome and network access locally (Selenium Manager fetches a matching driver the first time, and the card pulls IBM Plex from Google Fonts, the same stylesheet the layout itself loads). Both are build-time only: the generated PNGs are committed to the repository, and nothing at runtime or in CI depends on Selenium being available.
Generating cards
bin/rails og:images # every coding-agent page
bin/rails 'og:images[claude]' # just one, while tuning the layout
bin/rails og:images:docs # every docs category and page
bin/rails 'og:images:docs[mobile-apps]' # just one category
Docs cards land in public/og/docs/, named <category>--<slug>.png for an article and
<category>.png for a category's own index page. Both tasks share the same underlying renderer, so
adding a new docs page and running og:images:docs is the entire workflow; there's no design tool
involved.
Why a missing card fails loudly
If a page's card hasn't been generated, the site doesn't show a broken image; ApplicationHelper
falls back to the site-wide default card (/og.png) automatically, so nothing looks obviously
wrong in a browser. That silent fallback is exactly why a spec exists that checks every real page
and category has its own generated file, and fails the build if one is missing. See
spec/requests/docs_og_cards_spec.rb. Run the relevant og:images task, commit the new PNGs, and
the spec passes again.
Adding your own custom card
If a specific page wants a hand-supplied image instead of a generated one, blog posts support this
today through the image front-matter field, which overrides the generated fallback entirely. Docs
pages follow the same image field for the rare page that needs it, though most docs pages are
better served by the generated card, since it stays visually consistent with every other page in
the category automatically.
Next
You've now covered the whole content and SEO layer. See how the mobile apps reuse these same web views: Mobile Overview.