Understanding the AT Protocol: Grapheme Clusters, Rich Text Facets, and Bluesky Microblogging
A developer deep-dive into Bluesky AT Protocol (Authenticated Transfer Protocol) specifications, grapheme cluster character counting, rich text byte-slice facets, and decentralized microblogging APIs.
Bluesky operates on the Authenticated Transfer Protocol (AT Protocol)βan open, decentralized networking protocol designed for federated social applications. While traditional social networks measure post lengths using simple string length or UTF-16 code units, the AT Protocol uses strict Unicode Grapheme Clusters and UTF-8 Byte Slices for post character counts and rich text link facets.
1. What is the AT Protocol?
The AT Protocol enables federated social networking where user accounts (DIDs), posts, and follows are signed cryptographic records stored inside Personal Data Servers (PDS).
2. Bytes vs Code Points vs Grapheme Clusters
Counting text length accurately across international languages and emoji sequences requires distinguishing three concepts:
- UTF-16 Length: JavaScript's
"hello".lengthcounts 16-bit code units. Complex emojis likeπ¨βπ©βπ§βπ¦have a length of 11. - Unicode Code Points: The distinct numerical values assigned to characters. Emojis with Zero-Width Joiners (ZWJ) consist of multiple code points.
- Grapheme Clusters: What a human perceives as a single visual character unit (e.g.
π¨βπ©βπ§βπ¦is 1 grapheme cluster).
Bluesky posts enforce a hard maximum limit of 300 Grapheme Clusters per post.
3. Rich Text Facets & Entity Indexing
Unlike HTML where links are embedded as <a href="...">text</a>, Bluesky post text is kept completely plain. Web URLs, user mentions (@handle), and hashtags (#topic) are attached as Facets containing UTF-8 byte start and end indices:
// Post Payload Object
{
"text": "Check out DevBuildTool at https://devbuildtool.com today!",
"facets": [
{
"index": { "byteStart": 24, "byteEnd": 48 },
"features": [{
"$type": "app.bsky.richtext.facet#link",
"uri": "https://devbuildtool.com"
}]
}
]
} 4. Building an AT Protocol Post Counter
To accurately count Bluesky characters using modern JavaScript Intl APIs:
function countBlueskyGraphemes(text) {
// Use Intl.Segmenter for true Unicode Grapheme Cluster counting
const segmenter = new Intl.Segmenter('en', { granularity: 'grapheme' });
const segments = Array.from(segmenter.segment(text));
const count = segments.length;
const remaining = 300 - count;
const isOverLimit = count > 300;
return { count, remaining, isOverLimit };
}