For every one of my blog posts, my static site generator1 pre-computes an atproto TID defined by the post date time and its slug:

const TID_ALPHA: &[u8; 32] = b"234567abcdefghijklmnopqrstuvwxyz";

fn atproto_tid(date_rfc3339: &str, slug: &str) -> Result<String, minijinja::Error> {
    let dt = OffsetDateTime::parse(date_rfc3339, &Rfc3339).map_err(|err| {
        minijinja::Error::new(
            ErrorKind::InvalidOperation,
            format!(
                "atproto_tid(): first argument must be an RFC3339 date (e.g. post.date_iso); got '{date_rfc3339}': {err}"
            ),
        )
    })?;

    let micros = (dt.unix_timestamp_nanos() / 1_000) as u64 & 0x1F_FFFF_FFFF_FFFF;
    let digest = blake3::hash(slug.as_bytes());
    let clock = u16::from_be_bytes([digest.as_bytes()[0], digest.as_bytes()[1]]) as u64 & 0x3FF;
    let mut v = ((micros << 10) | clock) & 0x7FFF_FFFF_FFFF_FFFF;

    let mut out = [0u8; 13];
    for slot in out.iter_mut().rev() {
        *slot = TID_ALPHA[(v & 0x1F) as usize];
        v >>= 5;
    }
    // Every byte comes from TID_ALPHA (ASCII), so no UTF-8 validation needed.
    Ok(out.iter().map(|&b| char::from(b)).collect())
}

The TID is deterministic, given the a post's publication date and slug, so I then include it in the post’s HTML when it's rendered,

<meta name="atproto:rkey" content="3ms4qn7w2e2wc">

and also in the RSS feed

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:media="http://search.yahoo.com/mrss/"
    xmlns:atproto="https://github.com/vrypan/bckt/ns/atproto">
    
    ...
    
    <item>
      <atproto:rkey>3ms4qn7w2e2wc</atproto:rkey>
    ...

When, feed2sky2 picks the updated RSS, it checks if @robby.vrypan.net already has a post with this TID, and if not, it uses the post’s information in the RSS to publish one.

So, now there is a post like https://bsky.app/profile/robby.vrypan.net/post/3ms4qn7w2e2wc.


Using a pre-computed TID makes checking if the atptoto post already exists trivial. But there’s an other reason why it’s there.

My blog posts (remember, these are static pages, published before feed2sky published the atproto post), have a small js snippet3 that queries public.api.bsky.app/xrpc/ using @robby’s DID and the post TID, and if so, it shows a link with the number of likes, replies and reposts (at the time the browser visits the blog post).

Click the link bellow, to interact with this post on the atmosphere ;-)

  1. https://github.com/vrypan/bckt

  2. https://github.com/vrypan/feed2sky

  3. https://blog.vrypan.net/js/bluesky.js