How I publish Standard.site records from a Rails Bluesky delivery channel
Aotearoa, Again is a Rails app that publishes a daily colourised photo edition and fans it out to email, Instagram, Facebook, YouTube Shorts, and now Bluesky. I wanted those Bluesky posts to pick up the enhanced link cards Bluesky renders for Standard.site documents, instead of a plain Open Graph preview.
Standard.site is a set of AT Protocol lexicons for publications and documents. Bluesky reads those records (and checks them against your domain) to show publication branding on the card. What I needed in the delivery pipeline:
- One shared
site.standard.publicationrecord for the site - A
site.standard.documentrecord per edition - Proof both ways: the domain exposes the publication AT-URI, and each edition page points at its document record
- When posting, attach both refs on the external embed via
associatedRefs
One-off publication bootstrap
Creating the publication is a one-shot. A rake task calls a small service that uploads the site icon as a blob and creates the record:
# app/services/standard_site/publication_bootstrap.rb (trimmed)
record = {
"$type" => "site.standard.publication",
"url" => site_url,
"name" => SITE_NAME,
"description" => SITE_DESCRIPTION,
"icon" => icon_blob,
"basicTheme" => basic_theme,
"preferences" => { "showInDiscover" => true }
}
@client.create_record(collection: "site.standard.publication", record: record)
bin/rails bluesky:bootstrap_publication
That prints a publication_uri and
publication_cid
to paste into credentials alongside the Bluesky handle and
app password.
Re-run only when the
DID
or domain changes.
Domain verification is a plain-text well-known endpoint that returns the publication AT-URI:
# GET /.well-known/site.standard.publication
def site_standard_publication
uri = AppConfig.bluesky_publication_uri
return head :not_found if uri.blank?
render plain: uri
end
Domain verification can also be used to verify ownershipn of a handle (e.g. I own @aotearoa-again.joshmcarthur.com), but since a Bluesky account is a prerequisite for this integration, I chose to verify ownership using DNS rather than overloading the handle verification endpoint.
Per-edition delivery
Bluesky sits in the same deliveries table as the other channels. On publish
day, DeliverBlueskyJob:
- Creates (or reuses) a
site.standard.documentand stores its uri/cid on the delivery’smetadata - Uploads the share image as a blob
- Creates an
app.bsky.feed.postwith an external embed whoseassociatedRefspoint at the document and publication records
The embed side looks like:
"embed" => {
"$type" => "app.bsky.embed.external",
"external" => {
"uri" => uri,
"title" => title,
"description" => description,
"thumb" => thumb_blob,
"associatedRefs" => [
{ "uri" => document_ref.fetch(:uri), "cid" => document_ref.fetch(:cid) },
{ "uri" => publication_ref.fetch(:uri), "cid" => publication_ref.fetch(:cid) }
]
}
}
Edition pages close the loop with link tags once the document metadata exists:
<% if (document_uri = @edition.bluesky_delivery&.metadata_get("standard_site_document_uri")).present? %>
<link rel="site.standard.document" href="<%= document_uri %>">
<% end %>
<% if AppConfig.bluesky_publication_uri.present? %>
<link rel="site.standard.publication" href="<%= AppConfig.bluesky_publication_uri %>">
<% end %>
To check the card, paste a published edition URL into the composer on main.bsky.dev and confirm you get publication branding rather than a bare domain preview. For the records themselves, pdsls.dev is a useful debugger: paste a AT-URI and you get the raw JSON. Here’s Aotearoa, Again’s publication record, for example.