RSS ⧉

Blygger

Venkatesh Rao

The official blyg of the blygger protocol: RFCs open for comment, release announcements from every client, and technical notes. The spec itself lives at blygger.org/spec/.

thread

Introducing the official Blygger blyg

This is the official blyg of the blygger protocol. It sits beside blygger.org, which keeps the spec, and blygger.com, the directory of blygs. Anything about the protocol that announces a change or asks for a response is published here, so this is the one place to follow the project from a reader.

What appears here:

  • RFCs. Proposed conventions for clients, published for a comment period before any client builds them, so that a convention reaches the reference client only after other implementers have had their say. Each RFC is a thread, and the version under comment is pinned. To comment, respond from your own blyg: a stub is a comment, a partial quote names the passage you are answering, and a fork of the pinned version is a counter-proposal. Each RFC also links a GitHub issue for anyone without a blyg. The first two cover mentions across identifier schemes and comments sections.
  • Release announcements from every client. Releases of the reference client, and of any other blygger client, tool or integration. If you maintain one, open an issue on blygger/blygger-spec when you ship and the release will be announced here.
  • Technical notes. The design reasoning behind the spec, especially the designs it rejected, starting with TN-1 (versioning and pins) and TN-3 (groups). Their canonical text stays at blygger.org/notes/, which the spec cites; the copies here are where they take responses.
  • Spec revisions and snapshots, each announced with what changed.

What stays elsewhere: the spec itself, at blygger.org/spec/, and the reference pages on blygger.org such as the ecosystem list.

On bylines: most of what appears here is drafted by AI models and approved by Venkatesh Rao, whose name is the byline. Each such item discloses the model that wrote it, as this one does.

To follow, subscribe to https://blyg.blygger.org/ from any blyg-aware reader, or add https://blyg.blygger.org/feed.xml to an ordinary feed reader.

read the thread →

v2

“Markup fix: the post rendered inside a stray inline span.”

Created: Oct 7, 2026 Most recent: Oct 7, 2026, v2

thread

RFC-2 — Comments sections: a curated display of responses, every comment a real item

Request for comments · non-normative · OPEN FOR COMMENT until 2026-11-04 on blyg.blygger.org (#66); without a blyg, comment on blygger-spec#15 · session 40, 2026-10-07. Drafted by Opus 5.5 at Venkat Rao's request; edited the same session by Fable 5.1, whose rulings on the seven open questions are section 11. This proposes a Recommendation for clients that want a comments section. Like a technical note, an RFC constrains nothing. Blygger Studio will not implement it; its public responses list stays a citation trail. After the comment period it is published as guidance for the clients that choose to build it. It depends softly on RFC-1 (mentions across identifier schemes, section 9): kind 1 and kind 3 need nothing from it, kind 2 takes its address book, provenance and bylines, which is why the RFCs are ordered this way. Written against protocol 0.3 as published on 2026-10-07; no pre-1.0 version promises anything (#21).

The medium's first answer to "how do I comment" is from your own blyg (kind 1, section 5). Hosted comments (kinds 2 and 3) are an on-ramp for people who have no blyg yet, and the house that hosts them takes on their accountability. The comment period of this RFC runs that way itself: comments on it are stubs on blyg.blygger.org's RFC item (#66).

1. The question

Comments are the most requested feature from people running blygs. Venkat named three kinds:

  1. Responses from other blygs — Webmentions that fit a pattern, such as a stub with a short note, listed under the original item as comments.
  2. Signed-in commenters — people who sign in to this blyg with distinct identities and comment in an ordinary threaded comments section. Each comment goes out on the wire as an ordinary top-level item, so the thread is flattened to fit the spec.
  3. Anonymous commenters — if the owner chooses, a form whose submissions are vetted and then published as items under a byline such as anon or anon 7f3k.

This RFC recommends how a client builds all three, and argues that none of them needs a wire change.

2. The stance: no reply primitive, a comments section is presentation

The protocol has refused a reply primitive since #12 and says so at §16.8: "a network of soapboxes, not a conversation medium". §10.6 adds that a stub is "not a reply. There is no thread of replies, no conversation object". A Recommendation for comments sections has to leave that stance intact. It can, because the stance is about what the wire carries, and a comments section is what a page shows.

The whole recommendation rests on one idea:

A comments section is the owner's curated display of published responses. Every comment is a real item at some origin. Each one is a stub of the item it answers, under its writer's own byline. The tree is rebuilt from stub_of for display and never exists on the wire.

Everything the design needs is already built:

  • stub_of, the response marker (§10.6);
  • verified mentions, which tell an origin it was answered (§15);
  • curation display, which lets a page show other people's content with attribution (§13.5); §13.5 already names verified mentions as displayable under that rule;
  • per-item author, which puts many writers on one origin (§5.5, tn-3 shape B);
  • withdrawal, the only exit (§9).

What the protocol does not give is a way for anyone to put words on a target's page (§15.5). Under this design they still cannot. The owner displays responses, as curation, and can stop displaying any of them.

3. One display path for all three kinds

The three kinds differ in who publishes the comment and where. The comments section does not have to care, because each kind ends up the same way:

Kind Who publishes the comment At which origin How the original's page learns of it
1. Response from a blyg the responder their own a verified stub mention (§15.4)
2. Signed-in commenter the house, under the commenter's byline the house's comments origin (section 4) a verified stub mention, same as kind 1
3. Anonymous, vetted the house, under an anon byline the comments origin same as kind 1

So a client builds one renderer: the verified stubs of this item, with the stubs of those stubs nested beneath them. Kinds 2 and 3 are a publishing tool that the house runs on behalf of people who have no blyg.

4. Where house-published comments live: a comments origin

Kinds 2 and 3 are published by the house. There are two places they can go.

Option S — the same origin as the posts. This is conformant, but every comment is a publish event. §7 puts one feed entry per publish event, and §6.2 lists every item ever published. Subscribers to the house's essays would get every "great post!" in their reading list, every edit to a comment would resurface it, and every moderation withdrawal would leave a withdrawn entry in the feed. For a blyg with a handful of comments a month that cost may be acceptable. For a busy one it turns the house's soapbox into its own comment stream.

Option C — a sibling comments origin. Recommended. The house runs a second blyg next to the first, for example https://house.example/comments/ (path-mounted, #14) or https://comments.house.example/. All comments the house publishes go there. Each one is a stub whose stub_of names the post on the main origin.

Why C:

  • The main feed stays the house's own writing. Readers who want the conversation subscribe to the comments origin. Its blogroll entry, or a link on every post, makes it one click away.
  • It reduces kinds 2 and 3 to kind 1. A stub from the comments origin to the main origin is a cross-origin reference. It sends a real mention, and the main origin verifies it exactly as it would a stranger's. Since #61 a document under /comments/ cannot verify in the name of /, so the two origins cannot speak for each other even on one host. One renderer handles everything.
  • The house collects every reply to the comments it hosts. A reply to a hosted comment, from anyone, is a stub of an item on the comments origin, so the mention arrives there.
  • Accountability is legible. By tn-3's test, the comments origin is a masthead: the house withdraws anything on it and answers for everything on it, which is what moderation is. Its manifest author names the house, for example { "name": "House comments", "url": "https://house.example/" }.

The cost is a second origin with its own deployment, its own archive, its own Webmention endpoint (replies to hosted comments arrive there) and its own permanence (withdrawal endcaps are served forever). A client that offers comments should run both origins from one install, so the owner deploys one thing. The comments origin must also import the main origin as a subscription, because a partial transclusion in a comment resolves only against a local or imported item (§10.2); one install can share the store, but the resolution rule is the same.

5. Kind 1 — responses from other blygs as comments

5.1 What counts

  • Relation stub only. Being stubbed is being answered. Being transcluded is being quoted inside someone's own piece, and being forked is being descended from. Both are worth showing, but separately, for example as "quoted in" and "forked as" lists. Presenting them as comments would misstate what their authors did.
  • Comment versus response. A short stub reads as a comment and a long one reads as an essay. A client MAY show the full text of short stubs inline and only an excerpt plus a link for long ones. Measure the stubber's own words, leaving out the baked quote of this item (section 5.3). The threshold is presentation and the client's choice. §10.6 rule 2 tells readers to rely on the marker and never on body inspection. This does not break that rule: the marker alone decides that something is a response, and length decides only how much of it is shown (section 11, Q7).

5.2 Showing the text, and keeping it honest

§15.4 step 5 says a verified mention stores no content: "what it points at is fetched from its origin when displayed, or not at all." A comments section that shows text is therefore displaying another origin's content. The rules for that are §13.5's, and §13.5 names mentions explicitly:

  • Fetch on display, cache briefly, refresh. The receiver re-fetches the stub's live item document when showing it, through an ordinary HTTP cache. Edits are not reliably signalled: under §15.2, a stub whose target version did not change is not re-sent, so a refresh schedule is the only way to keep displayed text current (section 11, Q2–Q3).
  • Gone means gone. If the stub is withdrawn, re-fetched as an endcap, or the mention re-verifies as gone, it leaves the display. §13.4's retention rule applies as it does to any displayed import: show a pinned version only if the origin pins it, otherwise show nothing.
  • Attribution every time. Show the stubber's byline as their origin asserts it (§5.5 pass-through). Under RFC-1 it is an h-card, together with their origin and a link to the stub's page. A comment is never shown detached from where it lives.
  • Sanitize as an import (the reference reader's importer/sanitize.ts is a working model).

5.3 Strip the quote of this item

A stub usually starts by transcluding its target (§10.6 rule 2's aesthetic). Shown under the target, that quote repeats the post back to the reader. A comments display SHOULD collapse any baked blyg-transclusion whose data-blyg-id is this item and whose data-blyg-origin is this origin. A partial quote (blyg-partial) is the exception: it should stay, because "replying to this passage" is exactly what a reader needs to see. A collapsed whole quote can still show a small "quoting the post" marker.

5.4 Moderation

Display is the owner's act, so the owner decides who is shown. Clients SHOULD offer three modes per blyg, overridable per item:

  • pre-moderated — nothing shows until approved;
  • post-moderated — verified stubs show at once, and the owner can hide any;
  • trusted — post-moderated for origins in the owner's blogroll or address book, pre-moderated for everyone else.

The reference client's public responses list (studio, session 23) is the post-moderated mode, with links only. Hiding a comment is a display choice, never a delete: the stub is the stubber's speech on their own soapbox (§10.6), and it stays there.

5.5 Depth

Replies to a kind-1 comment stub that comment, so their mentions go to the commenter's origin, not to this one. This origin sees one level of external responses, plus any reply that also references this item. Showing "N replies elsewhere" would need a responses surface, and #41 and #47 closed that surface. Clients SHOULD show one level and link through. Kind 2 and 3 comments have no such limit (section 4: the house receives replies to everything it hosts).

6. Kind 2 — signed-in commenters

6.1 Signing in

The commenter signs in to the house's client with any provider the client supports:

  • IndieAuth, the best fit: it proves control of the commenter's own URL, which is #35's identity directly;
  • Mastodon or Bluesky OAuth, which yield an actor or a DID;
  • GitHub or Google, which yield a profile URL.

The client records the commenter in its address book (RFC-1 section 5.1):

  • the identifier from the login gets provenance bound, because the house checked it at sign-in;
  • the commenter's display name is theirs to set;
  • member stays false: a commenter is a guest, not a masthead writer.

Commenters receive a comment scope: a token in the shape #31 describes (bearer, owner-revocable), minted by the house's client to a guest at sign-in. This is the client's own guest authentication, part of the write surface #31 leaves to clients, and it borrows only the token's shape from the owner's tokens. It can do only:

  • publish a stub on the comments origin whose stub_of names an item on the main origin or the comments origin;
  • edit and withdraw that commenter's own comments;
  • nothing else: no drafts that last, no hoppers, no subscriptions, no studio.

The byline is fixed to the signed-in identity, and the commenter cannot choose it. This is the "a member is a token with a member's scopes" model (#38, tn-3 section 2), with a narrower scope.

6.2 What a comment is on the wire

A comment is a thread on the comments origin:

{
  "blyg": "0.3",
  "id": "3q8m1x…",
  "kind": "thread",
  "origin": "https://house.example/comments/",
  "author": { "name": "Ada Ruiz", "url": "https://ada.example/", "ids": ["did:plc:…"] },
  "stub_of": { "origin": "https://house.example/", "id": "7c9wk2…", "version": 4 },
  "content_md": "This is the part I'd push back on: …",
  …
}
  • Kind thread, because §10.6 makes stubs threads. A comment that quotes a passage of the post uses a partial transclusion (§10.1). That is the quote-reply comments sections have always wanted, and it is verified.
  • A reply to a comment is a stub of that comment. Its stub_of names the comments origin. The display rebuilds the tree by following stub_of chains, so the wire stays flat.
  • Edits are new versions (§5.2). They get no feed vocabulary, and the comments origin's feed shows the edit like any other publish event.
  • Delete is withdrawal (§9). The commenter withdraws their own comments, and the house withdraws anyone's, which is moderation. The endcap stays, and a reply to a withdrawn comment keeps its place in the display with a "withdrawn" placeholder.
  • Generated text is disclosed through generated[], as anywhere (§5.7). An agent can be a commenter under #38's rules: its own byline, an operator named, and content in every comment, since #36's line against content-free stubbing applies.

6.3 Limits a client should set

  • No transclusion of third parties by default. A transclusion of another origin in a comment sends a mention from the house's comments origin to a stranger, on a commenter's say-so. Allow quotes of this house's own items, and make anything wider an owner setting.
  • Pre- or post-moderation, as in section 5.4. Signed-in commenters are more accountable than anonymous ones, but a comment, once out, is on the wire for good: withdrawal leaves an endcap, and other readers may have quoted it.
  • Tell commenters what publishing means, in plain words at the comment box: the comment is public, it can be quoted, and deleting it leaves a "withdrawn" marker.

6.4 Commenters who have their own blyg

If the signed-in identity is a blyg origin, or the address book knows one for it, offer "respond from your own blyg" next to the comment box. That makes it a kind-1 comment, on their soapbox and under their accountability. A comment hosted by the house is the fallback for people without a blyg, not the default for people who have one (tn-3's withdrawal test applied to comments).

6.5 Portability

The commenter's verified URL is what keeps their comments recognisable if they later start their own blyg: RFC-1's ids and url match across origins once they are verified (#35 reader rule 2). As tn-3 section 5 says, the person is portable, the items are not.

7. Kind 3 — anonymous comments, vetted

This kind is entirely the owner's choice, and off by default in any client that offers it.

7.1 Flow

  1. A form on the item's page takes the text and, optionally, a display name. It has no URL field: a URL nobody verified is exactly the unchecked claim RFC-1 keeps off the wire.
  2. The submission enters a mandatory pre-moderation queue. For anonymous speech that is not optional, because approval is what makes the house's publication of it an editorial act rather than a pipe (#36). Machine triage MAY sort the queue. A person approves.
  3. On approval the house publishes a stub on the comments origin, exactly as in section 6.2, under an anonymous byline.
  4. The submitter receives a one-time withdrawal link at submission. Without an account, it is their only way to retract. Using it withdraws the item (§9).

7.2 The byline

  • {"name": "anon"} when the client does not tell anonymous commenters apart.
  • {"name": "anon 7f3k"} when it does. The suffix comes from a random token kept in the commenter's browser and is stable across their comments while the token lives. It MUST NOT be derived from an IP address, an email address or any hash of one: those can be reversed by trying candidates, and an "anonymous" label that can be reversed is worse than none.
  • No url, no ids. Nothing about an anonymous commenter is checkable, so nothing is asserted. Bylines that are byte-equal group only for display within this origin (§5.5), never across origins and never as an identity.
  • Readers see the house's assertion, as with every byline (§5.5). A client SHOULD label these comments "anonymous, approved by the editor" so that the house's role is visible.

7.3 Data the house keeps

Store only what vetting needs. Keep the text, the browser token and a rate-limit key, and delete the rate-limit key once a decision is made. Never put submission metadata into the item document. The house publishes the words, not the person.

8. Presentation rules common to all three

  • Different chrome for each source. "From their own blyg (verified)", "signed in via GitHub as ada.example", "anonymous, approved". #35's first reader rule says to show verified claims as verified and everything else as claims. A comments section that makes all three look alike erases the differences readers most need.
  • Order by observation time (§13.7), not by the commenter's self-asserted created. A stranger's clock does not get to move their comment to the top.
  • No counts. No "42 comments" and no per-commenter tallies. This is #12's and #13's no-metrics stance carried into presentation, the reason the reference responses list shows "a citation trail with no count", and the reason #47 kept a responses surface closed: a count is the first thing a ranking attaches to. A presence indicator ("Comments ↓") is enough.
  • No machine-readable comments markup on the post page. IndieWeb practice puts h-cite comment markup inside the post's h-entry. Doing that turns the display into exactly the machine-readable responses surface #41 tells readers never to parse and #47 declined. The comments origin already is the machine-readable record: real items, with real stub_of, in a real feed and index. Individual comments carry RFC-1's h-card bylines, which say who wrote something, not that it responds.
  • The comments section is never part of the item. It is not in content_html, not in the feed <description>, and not baked into anyone's transclusion of the post. Quoting a post never quotes its comments.

9. Wire impact: none

Nothing new appears anywhere a reader sees. The design uses only:

  • stub_of (§10.6);
  • author with RFC-1's conventional members (§5.5);
  • partial transclusion (§10.1);
  • withdrawal (§9);
  • verified mentions (§15);
  • curation display (§13.5);
  • mount independence for the comments origin (#14);
  • exact verification between sibling origins (#61).

No field, no relation, no feed element, no manifest key. A reader that knows nothing about comments sees a blyg (the comments origin) full of short stubs with different bylines, which is a correct reading of it.

The dependency on RFC-1 is real but soft. Kind 2 works with today's {name, url} bylines. RFC-1 supplies the address book, the bound provenance that sign-in produces, ids for recognising commenters across origins, and the h-card byline. A client could ship kind 1 and kind 3 before RFC-1 is settled. Kind 2 is where identity matters, and that is why the RFCs are ordered this way.

10. Rejected designs

Recorded because each will be re-proposed.

  1. A reply primitive or an in_reply_to field. stub_of already is "this answers that", verified. A second field would be a reply primitive (§16.8).
  2. A comment kind. Kinds describe what an item is (§5.3), and a comment is a short stub. A kind would ask readers to treat it differently, which is a version change by #43, for a distinction length already makes in presentation.
  3. Comments embedded in the post's item document, or carried in its content_html. That would put other people's words into this origin's item under this origin's content_hash, which re-emits them (§13.5) and lets stubbers write on the target's page (§15.5).
  4. A responses or comments list in the manifest or as a file. That is #47's closed surface, and the first place a count would attach.
  5. House comments on the main origin by default (option S). It is conformant, but it floods the house's feed (section 4). Clients may offer it for low-volume blygs, and should not default to it.
  6. Publishing anonymous comments without vetting. The result would be a pipe (#36) feeding permanent endcaps into every subscriber's archive.
  7. Pseudonyms derived from IP or email hashes. They can be reversed (section 7.2).
  8. Off-wire comments — an ordinary comment database rendered on the page and never published. This is not rejected: it is conformant, since the protocol governs only the page's protocol surface (#3) and says nothing about chrome. It is not recommended, because the comments then cannot be cited, quoted, forked or subscribed to, and they disappear with the client. The point of putting comments on the wire is that they become part of the medium. A client that wants Disqus can have Disqus.

11. Rulings (Fable 5.1, session 40, 2026-10-07)

The draft closed with seven questions. The rulings follow with the principle each rests on; where one differs from the draft's recommendation, it says so.

1. Fit with §16.8 and §10.6. Yes, on the wire: the design adds no field, no relation and no feed element, and a display tree rebuilt from stub_of is §10.6's own nesting, since a stub of a stub is a thread transcluding a thread. The character risk the draft names is real and is answered by framing, not by machinery: the header now says that the medium's first answer is to respond from your own blyg, that hosted comments are an on-ramp whose accountability the house takes on, and that the reference client's responses list stays a citation trail. Section 2's sentence, the owner's curated display of published responses, is the whole of what a comments section is, and the RFC must never describe a comment as a reply.

2. Displayed text against §15.4 step 5. A bounded cache is fetching on display. The rule exists so that a receiver never becomes a store of other people's words that outlives their withdrawal, and §13.5 names verified mentions as displayable under curation. The test a client must pass: if the stub's origin withdraws and the receiver never fetches again, the text must stop showing. So the cache has a bounded lifetime after which display requires revalidation, gone and an endcap purge it, and a durable copy exists only by the origin's pin (§13.4). This is only a kind 1 question; for kinds 2 and 3 the house is the publisher of the comment and holds it as its own item.

3. Edits are not signalled. (a) and (b), no spec change. The house controls the sender for kinds 2 and 3, so its comments origin re-sends a stub's mention when the comment is edited; §15.2 already permits it. For kind 1 the receiver refreshes on a schedule and accepts the staleness window. (c), a spec SHOULD to re-send on every stub edit, is rejected: it would make every edit of a stub notify its target, which is the noise §15.2 chose to permit and not require, and it is sender behaviour the spec would be changing for a presentation feature.

4. Steering clients toward a sibling origin. Confirmed, for the reason the draft gives: it is the only shape that keeps the house's own feed its own writing without new wire vocabulary, and it reduces three kinds to one renderer because #61 makes the two origins verify each other exactly as strangers would. It is not tn-3 section 6's pipe: every item on the comments origin is a person's words, published or approved by the house, which withdraws any of them. Two requirements are added to section 4: the comments origin imports the main origin so quotes resolve, and it runs its own Webmention endpoint for replies.

5. Counts and comments markup. Confirmed: no counts anywhere, no h-cite or other machine-readable responses markup on the post page. #12 and #13 refuse metrics, #47 kept the responses surface closed because a count is the first thing a ranking attaches to, and #41 tells readers never to parse one. The comments origin's feed and index are the machine-readable record, as the draft says. The h-card bylines inside comments say who wrote them and nothing more.

6. Anonymous bylines. Consistent with §5.5 and #38. author is the origin's unverified assertion, byte-equal values group only within one origin and only for display, and the origin is the accountable party. The three conditions in section 7 are what make it so and are kept as written: mandatory pre-moderation, a suffix that cannot be reversed to a person, and no url or ids. The withdrawal link must say what withdrawal is: permanent, and visible as an endcap.

7. Classifying by length. On the right side of §10.6 rule 2. The marker alone decides that an item is a response; length decides how much of it is shown, which is presentation. Measuring the stubber's own words by leaving out the baked blyg-transclusion of the target reads a wire token for the purpose it exists for, and is the same reading §5.6 rule 6 and this RFC's section 5.3 already make.

What happens next. Published for comment on blyg.blygger.org under #66 on 2026-10-07, after RFC-1; the period closes 2026-11-04. The reference client builds nothing from this RFC. A client that builds it is the gate for this RFC to become a technical note: one client hosts comments under this shape, and a second displays them as kind 1 responses. The decision list records these rulings beside RFC-1's (#67), with this section as the reasoning.

Source: docs/rfcs/rfc-2-comments-sections.md in blygger-spec, which is where revisions are made; each one is published here as a new version. To comment, respond to this item from your own blyg: a stub is a comment, a partial quote names the passage, and a fork of the pinned version is a counter-proposal.

read the thread →

v1 · pinned: v1

“RFC-2 open for comment until 2026-11-04.”

Created: Oct 7, 2026

thread

RFC-1 — Mentions across identifier schemes: petnames in the studio, full identifiers on the wire

Request for comments · non-normative · OPEN FOR COMMENT until 2026-11-04 on blyg.blygger.org (#66); without a blyg, comment on blygger-spec#14 · session 40, 2026-10-07. Drafted by Opus 5.5 at Venkat Rao's request; edited the same session by Fable 5.1, whose rulings on the five open questions are section 10. An RFC is a recommendation put up for comment before any client builds it, because the reference client shipping a convention reads as a blessing. Like a technical note, an RFC constrains nothing. After its comment period and the gate in section 10, ruling 1, it becomes a technical note. It builds on locked decisions #11 (the opaque author), #35 (identity practice, proposed in docs/proposals/identity-practice-proposal.md, which becomes tn-2), #36 (groups, tn-3), #20 (studio grammar versus wire grammar) and #32 ([[id]] is silent). Written against protocol 0.3 as published on 2026-10-07; no pre-1.0 version promises anything (#21).

1. The question

Several early users have asked for multi-author blygs, and with them comes a second request: @-mentions of the people who write there and of people elsewhere. The request (Venkat Rao, session 40) was for three things:

  1. a consistent recommendation for user identifiers within a domain that can travel through the protocol;
  2. an evaluation of how markup in the item body could carry the major identifier schemes — W3C DIDs, Ethereum accounts, ActivityPub, ATProto and h-card — so that clients sharing a convention can resolve @-mentions;
  3. a convention in which the client keeps an address book of contacts across schemes. The author types a short @handle, the client looks up the full identifiers in that address book, and the full identifiers travel on the wire, so that another client can resolve whichever scheme it speaks.

The third request is the design. Sections 2–4 clear the ground, section 5 is the convention, and sections 6–9 cover reading, scheme details, the reference client's default and what is rejected. Section 10 records the rulings.

The constraints are fixed. Authors are never addressable (§5.5, §16.8). The protocol has no reply primitive and no fourth mention relation (§16.8). The protocol has no normative write surface (#31), so nothing here comes from Micropub, in keeping with that decision while staying close to the IndieWeb in spirit. Whatever this RFC recommends has to be HTML and studio practice, not protocol.

2. Correcting a premise: the single author does not block multi-author blygs

The worry was that an item's author field holds only one name, so a multi-author blyg would have to sign everything as "community" unless the spec changed in a way that breaks RSS. Two parts of that are true and one is not.

  • A multi-author blyg does not need more than one name per item. author is per-item (§5.5). A masthead blyg with five writers publishes items whose bylines differ item by item. That is shape B of tn-3, specified since #11, and the feed rule is single-publisher, never single-author. "Community" is only needed if you want it: the Protocol Institute node already uses the byline "Editor".
  • RSS is not the binding constraint. In RSS 2.0, the core <author> element is a single email address, and the protocol does not emit it. The feed carries <dc:creator> (§7). Dublin Core lets that element repeat, and Atom allows several <author> elements. Many feed readers show only the first creator, which is a display limit, not a format limit.
  • The real single-valued thing is the protocol's own §5.5. author is one JSON object. Only co-authored items need more than one person in it, and §5.5's extension point already lets them carry more without a spec change (section 4.1 below).

So multi-author blygs work today and need nothing from the protocol. What the reference client lacks is studio-side: one author_name setting stamps every item (protocol.ts sets author.url to the origin). That is a client gap, and section 8 addresses it.

The census, re-run 2026-10-07 against the 20 blygs listed at blygger.com (19 reachable), the three newest items each: every item author is {name, url}, {name}, or absent. No client has invented an authorspace grammar, no item has two people in it, and no body contains an h-card or mention markup. Manifest-level author has grown bio, links and avatar in several clients. The per-item field is still empty, so this is still the cheapest time to recommend something.

3. Identifiers within a domain

In shape B (one origin, many bylines), what identifies a member? The answer follows from #35's spine — a person is a URL they control — with one concession for people who have no URL of their own:

Member has… author.url What it proves
their own site, profile or actor URL that URL portable. If the page links back (section 5.5), a reader can confirm the byline from the member's side.
nothing of their own a house-hosted member page, e.g. https://house.example/people/alice/ only that the house says so. That is honest: in shape B the house answers for everything (tn-3 section 5).

The member page is presentation. It is an HTML page like any page, not a protocol construct, so it does not make authors addressable in §16.8's sense: nothing in the protocol references it. It has a second job, which section 5.5 gives it: it is the origin-side end of the reciprocal proof for a member who does have their own URL. A member who later moves to their own origin (shape A) takes their own URL with them. A house URL does not travel. That is the practical reason to prefer the member's own URL whenever they have one.

No user@domain grammar inside an origin. @alice as typed in the studio is a petname, a name that is meaningful only in this address book (section 5). It never reaches the wire as an identifier. DNS remains the namespace (#11).

4. The five schemes, evaluated

Each scheme answers four questions:

  • What is its stable identifier, as opposed to its human-readable name?
  • Can a reader resolve it with an ordinary fetch?
  • How does a person prove control of it?
  • What does it reduce to under #35's two proofs: a reciprocal link, or a signature?
Scheme Human name (mutable) Stable identifier to put on the wire Resolution Proof Reduces to
Web / h-card the URL itself https://alice.example/ fetch, then parse the representative h-card rel="me" reciprocal links link (it is #35)
ActivityPub @alice@social.example acct:alice@social.example (RFC 7565), plus the actor's https URL WebFinger (RFC 7033) maps acct: to the actor URL Mastodon-family servers check rel="me" on the links in a profile and serve rel="me" on profiles themselves link
ATProto handle alice.example or alice.bsky.social the DID, usually did:plc:… DNS TXT _atproto.<handle> or https://<handle>/.well-known/atproto-did, and the DID document's alsoKnownAs points back two-way handle↔DID binding. A domain handle is DNS control. link (a domain handle is a URL the person controls)
W3C DID none did:<method>:… method-specific. did:web is an HTTPS fetch. did:plc needs a directory. did:key and did:pkh resolve locally. did:web: DNS. Others: a key in the document did:web reduces to a link. The others reduce to a signature.
Ethereum ENS name alice.eth the account as a DID, did:pkh:eip155:1:0xAb… (the CAIP-10 account eip155:1:0xAb… wrapped; see section 7) ENS needs chain access (an RPC endpoint); the account needs nothing EIP-191 signature (e.g. over content_hash, #35 §4.2); EIP-4361 for sign-in signature

Four observations decide the design.

  1. h-card is not a rival scheme. It is the envelope. It is the IndieWeb's format for "here is a person and their identifiers": p-name, u-url (which may repeat), u-uid, and u-key. Every other row can be written inside an h-card. That makes it the natural carrier for request 3, and it is already how Mastodon marks up mentions in HTML (<span class="h-card"><a class="u-url mention" href="…">@<span>alice</span></a></span>).
  2. Put the stable identifier on the wire, never the name. ENS names expire and transfer, ATProto handles change, and fediverse accounts migrate. The address, the DID and the actor's acct: are what a distant reader can still match a year later. The web is the exception, because the URL is both the name and the identifier. That is exactly why #35 chose it.
  3. Three of the five reduce to "a URL the person controls". Those are the web, ActivityPub, and ATProto with a domain handle. did:web joins them. Only did:plc/did:key and Ethereum need a signature or a non-HTTP resolver. The default can therefore stay boring (section 8) and lose almost nothing.
  4. The schemes differ in cost to the reader, not just in reach. Resolving an ENS name needs chain access, and did:plc needs a third-party directory. A static reader cannot do either. Any convention has to work for a reader that resolves nothing, and that pushes the visible fallback onto a plain https link.

A fifth, smaller observation sets the wire vocabulary: with Ethereum accounts written as did:pkh:, everything on the wire is an https:, acct: or did: URI. Three schemes, three normalization rules (section 6), and a matcher needs nothing else.

4.1 What author can carry for co-authored items

A co-authored item keeps one author object, as §5.5 requires. It can use the extension point §5.5 grants, so no spec change is needed:

"author": {
  "name": "Alice Ng and Bob Ruiz",
  "url": "https://house.example/",
  "coauthors": [
    { "name": "Alice Ng", "url": "https://alice.example/", "ids": ["did:plc:7iza6de2dwap2sbkpav7c6c6"] },
    { "name": "Bob Ruiz", "url": "https://social.example/users/bob", "ids": ["acct:bob@social.example"] }
  ]
}

A reader that knows only name shows "Alice Ng and Bob Ruiz", which is correct. <dc:creator> carries the same combined string. Emitting one <dc:creator> per person is legal, but readers that show only the first would drop Bob. For a single author, ids sits directly in author beside url. ids is the same array as a mention's alternate identifiers (section 5), with the same emission rule, and is ruled in as a conventional member in section 10, ruling 5. It is distinct from the manifest-level links that several clients already emit: links are labelled links for display, ids are identifiers for matching.

5. The convention: an address book of petnames, full identifiers on the wire

This is the design the request asked for. It takes its shape from petname systems, and in particular from Zooko's triangle. Zooko's observation was that a name cannot be global, secure and memorable all at once. The standard resolution, used by Stiegler's petname designs and by every phone's contact list, is to keep the memorable name local, to the person who chose it, and to send the global, secure identifier. @kyle is memorable only in one studio. did:plc:… is global and verifiable but nobody can type it. So the address book holds the mapping, and the wire carries only what other clients can check.

5.1 The address book (studio-private)

Each contact record holds:

  • handle: the petname the author types (kyle). It is unique within the book. It never leaves the studio.

  • name: the display name used when the mention renders.

  • url: the primary https URL, used as the link target. It is optional only for a contact who has no web presence at all, for example an Ethereum-only contact.

  • ids[]: alternate identifiers in their stable form (section 4 observation 2). Each carries provenance:

    • self means the contact publishes it themselves, for example as a rel="me" link or an h-card u-url at their url, or as an alsoKnownAs entry in their DID document;
    • bound means the scheme's own two-way binding was checked. Examples are a handle and DID that point at each other, or WebFinger agreeing with the actor;
    • entered means the author typed it in, and nothing has checked it.
  • member: true for people who publish at this origin. In shape B the house's member roster is simply the book's member entries. The roster supplies each member's byline, and the members sign in with #31's scoped tokens. The roster changes nothing about accountability: the house still withdraws any item and owns every pin (tn-3 section 5).

How the book fills itself. When the author adds a contact by any single identifier, the studio resolves outward from it and gathers what it can:

  • from a URL, it fetches the page and reads the representative h-card and the rel="me" links, which reveal the person's fediverse, Bluesky and GitHub profiles, all self;
  • from @alice@social.example, it runs WebFinger, reaches the actor, and reads the actor's profile links;
  • from an ATProto handle, it resolves the DID and checks the DID document's alsoKnownAs;
  • from did:web, it fetches the DID document.

Subscriptions supply contacts for free: every subscribed blyg's author already carries a name and url, and the studio can offer to add it.

5.2 Writing: @handle is studio grammar and is consumed at publish

The editor offers autocomplete on @. The grammar is studio-private under #20's two-layer split, like TK. It is consumed at publish, and it never appears in content_md:

  • @kyle that matches a contact turns into a mention.
  • @word that matches nothing stays literal text, and the editor shows a soft warning with an "add contact" action. It is never a publish error, because @ is common in prose, in code and in email addresses. Text in code spans and code blocks is never touched, which is the same rule as #54.

Why it must be consumed rather than left in content_md: forkers re-parse content_md (#63). If @kyle stayed in the text, it would travel to a forker whose address book has no kyle, or a different one. That would make one person's petname resolve to another person in someone else's fork. Under #43's boundary test, a grammar that a third party has to re-parse belongs to the protocol. This one must not become protocol (§16.8), so it must not survive publish.

The same fact sets what a fork keeps. A forked thread descends from the pinned document (#57), so its baked content_html carries the h-cards. A forked fragment is re-rendered from content_md (#63), so it carries the plain link and not the alternate identifiers, unless the forking client's own book knows the URL and re-wraps it. That is correct: the identifiers were the original publisher's statement about their contact, and a fork is the forker's speech.

5.3 What goes on the wire

In content_md: a plain markdown link, which any markdown reader understands:

Thanks to [@Kyle Mathews](https://bricolage.io/) for the edge-cache work.

In content_html: the same link, wrapped as an h-card that carries the contact's alternate identifiers:

<span class="h-card"><a class="u-url" href="https://bricolage.io/">@<span class="p-name">Kyle Mathews</span></a><data class="u-url" value="did:plc:7iza6de2dwap2sbkpav7c6c6"></data><data class="u-url" value="acct:kyle@social.example"></data></span>

The markup follows these rules:

  • The visible anchor is the contact's https URL. A reader that knows nothing about h-card shows a link, and clicking it works. A contact without a URL renders as <span class="h-card">@<span class="p-name">Name</span>…</span>, which shows a name with no link. The @ sits outside p-name, so a parser gets the name and the page gets the sigil.
  • Each alternate identifier is a <data class="u-url" value="…">. microformats2 parsers read <data value> for u-* properties, and u-url is allowed to repeat. <data> renders nothing, so readers that ignore it lose nothing. All these values are absolute URIs, so §5.2's rule that content_html is self-contained holds.
  • Only self and bound identifiers go on the wire by default. The entered identifiers stay in the book. Putting an unchecked DID beside someone's URL tells every reader that the two are the same person, and the author never verified that. The author MAY choose to publish entered identifiers per contact, but the studio should not do it unasked.
  • Order carries no meaning. The anchor's href is the primary identifier; everything else is unordered.
  • Mentions are silent on the wire, in exactly the sense in which [[id]] is silent (§10.1, #32). They add no transclusions[] entry, no relation (§15.4) and no new field, and they send nothing (section 10, ruling 2).

Why this is not a spec construct: the markup is ordinary HTML using a published W3C-community vocabulary, inside a field that already accepts any editorial HTML. No reader, receiver or publisher has to change for it to work, so it fails every part of #43's test for protocol. It uses no blyg- class and no data-blyg-* attribute. Those prefixes are spec vocabulary (§10.2), and using one would turn this into a spec construct by the back door.

5.4 The byline uses the same record

When a member publishes, the studio fills author from their contact record: name, url, and the same filtered ids. A permalink page renders the byline as an h-card (p-author h-card) inside the item's h-entry. A microformats-aware reader then gets the byline and the mentions from one parse, and the item becomes a valid IndieWeb post without any work on the reader's part.

5.5 The proof on a shared origin

#35's proof is a reciprocal rel="me" link: author.url names a page that links back to the identity origin, and the sentence both links make is "this is also me". For a one-person blyg that sentence is true in both directions. On a shared origin it is false in one: Alice is not the house.

The ruling (section 10, ruling 3) keeps the proof and moves its origin-side end. On a shared origin the reciprocal rel="me" runs between author.url and the member's page under the origin (section 3), and both directions are now true statements, because both pages are Alice:

  • https://alice.example/ carries <a rel="me" href="https://house.example/people/alice/">;
  • https://house.example/people/alice/ carries <a rel="me" href="https://alice.example/">.

A reader verifying a byline fetches author.url and looks for a rel="me" link whose href is either the identity origin itself (#35 as written, the one-person case) or a URL that has the identity origin as its prefix (the shared case). In the second case it fetches that page and requires a rel="me" back to author.url. Two bounded fetches, cached per (author.url, origin) pair, and the result is shown with the same chrome as any other verified claim: there are two states, verified and claim, and this adds no third. The house can write whatever it likes on its side of the pair, but the house is already the party asserting the byline; what it cannot forge is Alice's page, which is exactly the half #35 relies on. A member whose author.url is the house page has nothing on the far side to check, and the byline stays a claim, as section 3 says.

This is also what makes tn-3 section 5's portability concrete: when Alice leaves, the house removes its rel="me", Alice's page points at her new origin, and the same reader rule follows her there.

5.6 Agent members

An AI that runs on the same client as the human publisher and publishes with a member's rights needs almost nothing from this convention, because #38 already settled the protocol side: an agent is a valid opaque author, at the studio it is a token with a member's scopes, and the protocol never asks who acted. Four client-side accommodations remain, none of them on the wire.

  1. The roster says what the client cannot tell. A member: true record can be a person or an agent, and nothing in a token reveals which. An agent member's record carries operator, the URL of the human or organisation that answers for it (tn-2 section 7), and a declared model. Both flow into what the studio stamps on the agent's items.
  2. The token scope decides the byline. #52 already requires publishing to be a distinct verb from drafting, and that distinction is #38's response-versus-pipe line made mechanical. A draft-only token means a human approves and publishes: the human's byline, and one generated[] span naming the model. A publish-scope token means the agent publishes on its own initiative: the agent's byline with operator, and a whole-item generated[] span. The byline says who, the provenance says how, and the operator says who answers; none of the three is collapsed into another.
  3. Provenance in the address book is set by the resolver, never by the caller. No API path may assert self or bound. Anything an agent adds to the book is entered and stays off the wire until the studio resolves it. Without this rule an agent holding a contacts scope becomes the identity broker that rejected design 5 guards against. The publish API also returns unresolved @word warnings in machine-readable form, since an agent never sees the editor's soft warning.
  4. No pin or withdraw scopes for agent tokens by default. A pin is an irrevocable hosting promise and withdrawal is the only exit; tn-3's test says the house answers for both. Scope names are the build's (#52), and the default is conservative.

Two of the rulings in section 10 are what make agents safe here. Ruling 2, mentions are silent, matters most: an agent writing a hundred items with @-mentions produces no notifications, where an opt-in would have been the flood tn-3 section 6.2 describes by another route. Ruling 3 covers the byline: an agent with only a house member page stays a claim, which is honest, and operator is likewise a claim by the origin, the party already accountable under invariant 4, so there is nothing further to prove.

One question is left to the client: whether a house with several human members shares one address book or keeps one per member. Petnames are personal by construction, and a shared newsroom contact list is also ordinary practice. Either works with everything above.

6. Reading: resolving a mention in the scheme you speak

A receiving client finds .h-card elements in content_html and collects the href and the <data class="u-url"> values. It then does whatever its own schemes allow:

  • Match against its own address book. It normalises each identifier per scheme, three rules for three schemes:

    • https URLs: as §15.4 normalizes an origin — scheme and host case-insensitive, default port dropped, trailing slash normalized;
    • acct: identifiers: compare case-insensitively;
    • DIDs: compare exactly, except that a did:pkh:eip155:… account is compared case-insensitively on the address, and a bare CAIP-10 eip155:… met in the wild is read as the same account (section 7).

    The client then looks for a contact holding any of the identifiers. On a match it MAY show the mention as the reader's own contact, under the reader's petname.

  • Resolve schemes it speaks. An ATProto-aware reader can link the DID to a Bluesky profile, a wallet-aware reader can show the ENS reverse name, and a fediverse-aware reader can offer to follow the actor.

  • Do nothing. The link still works, which is the floor.

Three rules protect readers. They mirror #35's reader rules:

  1. A relabel replaces the whole mention. If the reader shows its own contact's petname, it also uses its own contact's URL as the link. Otherwise a publisher could pair the victim's DID with the attacker's href, and a reader would print the victim's name over the attacker's link. With this rule, a forged pairing makes the reader show its own, correct contact, with no way to redirect the click.
  2. A mention's identifiers are the publisher's claim and never prove anything. An h-card that lists a URL and a DID together does not tell the reader that they belong to one person. A reader MUST NOT add a mention's identifiers to its own contact record without checking them. This is #35's rule against merging identities across origins without a verified claim, applied to mentions. A match against the reader's book is a display decision, never a merge (§13.1 rules 5 and 7).
  3. No counts and no gating. "You were mentioned 40 times" is a follower metric by another name (#12, #13). A client may list mentions of a contact for its own owner. It never publishes them as a number.

Quotations carry other people's mentions. A baked transclusion copies the source's content_html, h-cards included (§10.2, verbatim). Those mentions are the quoted author's speech. The quoting client MUST NOT treat them as its own, whether for notification, for its book, or for display as "mentioned by me".

The reference reader's sanitizer drops this markup today. blygger-studio/src/importer/sanitize.ts keeps class, but data is not in its tag list, so the element is unwrapped and its value removed. It also strips any href that is not http(s)/mailto/tel, which is right. The fix is small: allow the <data> element with value (inert text, never fetched). Without it, the reference client would publish the full identifiers and then throw them away on every read. Other clients' sanitizers will vary. Every reader keeps the visible link, so the design degrades to an ordinary link.

7. Scheme notes

  • ActivityPub. On the wire, an acct: identifier plus the actor URL as href. Actually notifying a fediverse account requires delivery to its inbox as an ActivityPub actor. A blyg is not an actor and should not become one in order to do this. Bridges such as Bridgy Fed, which turn Webmention-sending web sites into fediverse presences, are the route for anyone who wants it, outside the protocol.
  • ATProto. Emit the DID, not the handle. A handle that is the person's own domain is the best case of all: their url is https://alice.example/ and their DID resolves back to that domain. One record then counts as bound in two schemes.
  • DIDs. did:web is a URL with extra steps (#35). Other methods are stored and emitted when self (listed in the person's h-card or rel="me" links) and are otherwise left to clients that resolve them.
  • Ethereum. Emit the account as did:pkh:eip155:<chain>:<address>, which is the CAIP-10 account in DID clothing and the same bytes. Writing it as a DID keeps the wire to three URI schemes and spares readers a fourth normalizer; readers accept a bare eip155:… as the same account. ENS is an input convenience, because a name that can expire must never be the wire identifier. Proof of control is a signature, which is #35's second proof. A signed byline (EIP-191 over content_hash) is that proposal's mechanism, unchanged. Whatever the address book does, a wallet scheme is meaningful in a mention only when the person themselves published the address at their URL.
  • h-card. It is the carrier format. The contact's own representative h-card is also where the book learns their other identifiers. In practice, a person who wants to be mentionable across schemes lists them on their home page.

8. Recommendation for the reference client

The client should stay boring (the ruling that tabled blygger-studio#35: "studio should be boring"), so its default is narrow, and every wider scheme belongs in other clients or in extensions.

  1. Per-item bylines from a member roster, which closes the real multi-author gap. A member's author.url is their own URL when they have one, otherwise a house member page. Tie this in with #31 tokens so each member's scoped token publishes under that member's byline.
  2. An address book with @handle autocomplete, consumed at publish into a markdown link in content_md and an h-card in content_html, as in section 5.
  3. Schemes it resolves when a contact is added: https (h-card and rel="me"), fediverse handles (WebFinger) and ATProto handles (DNS or well-known, giving the DID), plus did:web. These all reduce to a URL or a DNS check, and none of them needs a vendored dependency (the session-29 ruling).
  4. Schemes it stores but does not resolve: other DIDs and did:pkh accounts. It accepts them as entered, and emits them only when the contact's own page lists them. ENS lookups, wallet sign-in and signature checking belong in an extension, not the base client.
  5. Its sanitizer keeps <data value>, so it reads the markup it writes.
  6. No notification. A mention is silent like [[id]]; the reference client sends no Webmention for one, and offers no switch to (section 10, ruling 2).
  7. Byline verification on a shared origin follows section 5.5 when the reader side of #35 is built: one rule, two fetches, two display states.
  8. Agent members per section 5.6: operator and model on the roster record, the byline chosen by the token's scope, resolver-only provenance in the book, publish warnings returned by the API, and no pin or withdraw scopes on agent tokens by default.
  9. Later: IndieAuth for member sign-in. IndieAuth proves that a member controls their URL at the moment the house mints their token, so the roster's url becomes verified from the member's side without a second fetch. It fits #52 (an OAuth-style minting flow) and is the one IndieWeb spec besides Webmention and microformats that the studio has a use for.

Of the five schemes, the reference client should emit h-card markup and recognise the web, ActivityPub, ATProto and did:web natively, and treat Ethereum and other DID methods as data it carries but does not interpret. The full identifier list still goes on the wire for every scheme, which is what lets a wallet-aware or ATProto-native client resolve what the reference client only carries.

9. Rejected designs

Recorded because each will be re-proposed.

  1. An @ construct in the spec (a MAY directive in §10.1, a mentions[] field in the item, a blyg:mention feed element). Rejected because it would make authors addressable (§16.8). It would also add a reference kind that receivers would be expected to act on, which is a reply primitive by another route. Finally, it would freeze one identifier vocabulary into a permanent surface while the schemes themselves keep moving.
  2. Leaving @handle in content_md for each reader to resolve. A petname means something only in the book that defined it. Shipping one gives every forker and reader a name that resolves to whoever they call kyle (section 5.2).
  3. One canonical scheme that everyone must use (all DIDs, or all fediverse). This picks a winner among live communities. It also adds a resolver as a dependency for every reader. The census shows that the field already chose the URL.
  4. user@domain addressing inside a shared origin. Closed at #11 and again in tn-3 section 8: the path or subdomain already serves as the namespace.
  5. Putting entered identifiers on the wire by default. That would make every author an unwitting identity broker, publishing guesses about which accounts belong together.
  6. data-blyg-ids. It would survive today's sanitizer because of the data-blyg- prefix. Rejected because that prefix is spec vocabulary, and using it here would add a construct silently. Fix the sanitizer instead.
  7. Micropub as the members' write path. No normative write surface (#31). The studio's own API with scoped tokens already serves the purpose.
  8. Salmention-style propagation of mentions upstream. It pushes other people's responses onto a target's page. §15.5 forbids that: nothing lets a stubber put words on the target's page.
  9. A Webmention for every mention, or an opt-in switch for one in the reference client. A mention is a link, and a link notifies nobody (#32). The reasoning is section 10, ruling 2; what a client that does send must respect is there too.
  10. An "acknowledged" display class between verified and claim, for a member's link to a shared origin. Rejected because any link from Alice's page to the house proves only that Alice linked to something there, and a third chrome state is more display for less proof. Section 5.5 keeps the reciprocal rel="me" and two states.
  11. Bare CAIP-10 as the wire form of an Ethereum account. It is a fourth URI scheme for the same bytes did:pkh: already carries (section 7).

10. Rulings (Fable 5.1, session 40, 2026-10-07)

The draft closed with five questions. The rulings follow, each with the principle it rests on; where a ruling differs from the draft's own recommendation, it says so.

1. Sequencing. The route is confirmed, and where it runs was decided the same session (decision #66): the project's own blyg at blyg.blygger.org carries RFCs, and comment periods run there. (a) This edited draft is published as a thread on that blyg, with a stated close date in the text; the version under comment is pinned, a revision during the period is a new version, pinned in turn when comments should move to it. (b) Comments are the protocol's own responses: a stub of the RFC item, whose stub_of.version records which draft it answers; a quote is a partial transclusion; a counter-proposal is a fork from the pin. Anyone without a blyg can open an issue on blygger-spec instead, and the item says so. There is no RFC section on blygger.org. (c) Nothing in section 8 is built in the reference client until the period closes. (d) After that, the RFC becomes a technical note of its own by the gate #35 uses for tn-2: one client emits mention h-cards and a second resolves them. It does not fold into tn-2. That note's subject is one person's URL and the two proofs of it; this one's is a client convention for naming other people, and folding them would make the identity note carry a studio design. Two rulings here are about author rather than about mentions, and tn-2 absorbs them when it is written: the shared-origin proof (ruling 3) and ids (ruling 5). The git file stays the single source throughout; the blyg publishes versions of it, never hand-edited copies (#66).

2. A mention does not notify. Mentions are silent, and the reference client sends nothing for one and offers no switch to. This is #32's principle carried over, not a new one: a link asserts nothing on the target's behalf, so a receiver has nothing to verify, and a notification with no verifiable claim behind it is the trackback class §15.6 holds down. The @ form is a link with a better name, and it inherits the link's silence; "@ notifies" is an expectation from media with reply primitives, which this one refuses (§16.8). Two further facts settle the edges. §16.8's bar on a fourth relation is not in play either way, because a mention's target is a person's page and never an item; §15 governs mentions between blyg items, and this was never a §15 question. And where a person's URL happens to be a blyg page, a plain Webmention to it is refused outright (§15.3 step 1: the target must name a published item) or marked failed (§15.4 step 4), so it could only ever cost the receiver fetches. What remains is the open web: any client may send a W3C Webmention to a non-blyg page for a link it publishes, as IndieWeb sites do, and this RFC neither blesses nor forbids that. A client that does so should observe three things: never to a target inside a blyg origin; never for an h-card inside a baked quote (§10.2 verbatim, the quoted author's speech); never by default, only per mention at the author's choice. This differs from the draft, which recommended a per-mention opt-in in the reference client. The client stays boring (blygger-studio#35), and the one way to cite without notifying stays wide.

3. Reciprocity on a shared origin. Not an acknowledgement class. The proof is #35's reciprocal rel="me", unchanged; what moves is its origin-side end, from the origin to the member's page under it (section 5.5). Both links then say "this is also me" truthfully, because both pages are the member. The reader rule is one rule with two acceptable far ends: the identity origin itself, or a page that has it as a prefix and links back. Two fetches, two display states, no third chrome. The draft's alternative, any link from author.url to the origin shown as "linked from", was rejected because a link proves that the member linked to something at the house, not that they write there, and because a third state is more display for less proof (section 9, item 10). This is a ruling about identity semantics, so it is Fable's under #58, and tn-2 carries it when written. tn-3 section 5 already promised that a verified byline survives a move from shape B to shape A; this is what makes that true.

4. The spec says nothing. Confirmed. A sentence about preserving microformats in content_html would be the spec's first word, however indirect, about identity markup, and #11's silence on identity is a principle rather than an omission. Under #43 it would in any case be a revision that readers already handle, and a convention one client emits is not yet a reader question. The fix lives in the reference client's sanitizer (section 8, item 5). Revisit when a second client emits the markup and a sanitizing reader's loss of it has caused a failure someone can name; the candidate home would be §13.1, not §5.2.

5. ids in author. Allowed as a conventional member, filtered as section 5.3 filters mentions. #35 already places two conventional members in author, the signature and an agent's operator, so a third of the same character adds no principle. The shape: an unordered array of absolute URIs in the three wire schemes, https:, acct: and did: (Ethereum as did:pkh:, section 7), each self or bound from the member's own publications. Because of that filter the house relays what the member publishes about themselves and asserts nothing new. §5.5's pass-through rule binds ids as it binds every author member, and §13.1 rules 5 and 7 still hold: a reader matching ids against its book is making a display decision, never a merge. The draft's reason stands as the practical one: a reader should not need a fetch to match a byline against its address book.

What happens next. Published for comment under ruling 1 on 2026-10-07; the period closes 2026-11-04 (four weeks, as recommended). Revisions during the period are made in this file and republished as new versions of the same item. The decision list carries one entry for the five rulings (#67), with this section as its reasoning.

Source: docs/rfcs/rfc-1-mentions-and-identifier-schemes.md in blygger-spec, which is where revisions are made; each one is published here as a new version. To comment, respond to this item from your own blyg: a stub is a comment, a partial quote names the passage, and a fork of the pinned version is a counter-proposal.

read the thread →

v1 · pinned: v1

“RFC-1 open for comment until 2026-11-04.”

Created: Oct 7, 2026

thread

TN-3 — Groups need no new construct: N origins, one masthead, and the stubbing anti-pattern

Technical note · non-normative · session 28, 2026-09-28 (Opus 5, writing up decision #36 — ruled session 27 by Fable + Venkat). Decision record for locked decision #36. Technical notes record design reasoning — especially rejected designs — alongside the normative spec; they constrain nothing and are citable rationale, not protocol. Written against protocol 0.3 as published on 2026-09-28; every construct named here is built and live, but no pre-1.0 version promises anything (#21), so check the living text before you lean on a detail.

Revised session 38, 2026-10-06 (Opus 5.5), after decision #61: §3 gains the consequence that members on one host cannot verify mentions in each other's name, which was not true of the 0.3 text this note was first written against.

1. The question

Two requests arrived from early users within days of the first strangers standing up their own blygs:

  1. "A multi-user blyg with separate folders." A publication or workgroup wants several people writing under one roof, each with their own space.
  2. "An aggregator that stubs everything." A site wants to be the one place to follow a group, and proposed doing it by emitting a stub for every item the members publish.

Both read like requests for a new construct — a group, a space, a members list, a pipe. Neither is. The first decomposes into two shapes the protocol already has, distinguished by one question; the second is an anti-pattern, and the interesting part is why it cannot be stopped by a rule.

The spec's own involvement in all of this is two sentences of documentation: a warning in §10.6 and the honest shape named in §13.5. This note is the reasoning behind those sentences.

2. There is no folder on the wire

Start with what "separate folders" would have to mean. A blyg is a directory of files under an origin: one blyg.json, one feed.xml, one items/index.json, and item documents (spec §4). Every reference in the protocol — transclusions[], stub_of, forked_from — names {origin, id, version} (§5.9). Subscription targets an origin (§12.2). Withdrawal is an act by an origin about its own item (spec §9). Pins are hosting promises made by an origin (spec §8).

Nothing in that list has a place to put a folder, and adding one would mean adding an addressable sub-identity beneath the origin — which is exactly what #11 refuses ("authors are never addressable … permanently") and what invariant 4 refuses one level up ("the only authenticated entity is the publishing client at its domain").

So the folder, if it exists, is a studio view: a way of organising the authoring tool, invisible on the page, which is precisely where #1's studio/page split puts it. Members in the studio are #31's scoped bearer tokens — owner-minted, owner-revoked, per-client, with coarse verb scopes. A member is a token with a member's scopes, and the wire never learns that any of this happened.

What the request actually asks, once the folder is set aside, is: how many origins? There are two answers, and they are different protocols of trust, not different implementations of one.

3. Shape A — N origins under one host

Mount independence (#14) means a blyg's origin is any absolute base URL, and no protocol construct may infer anything from the path. So one host serves as many blygs as it likes:

https://house.example/alice/     blyg.json, feed.xml, items/…
https://house.example/bob/       blyg.json, feed.xml, items/…
https://house.example/           the house's own blyg (optional)

Subdomains work identically (alice.house.example) and were exercised in the wild by a stranger who path-mounted at /blyg/ without being told it was allowed.

The index is a blogroll. The house publishes blogroll.opml (§11) listing its members. A reader importing that one OPML file subscribes to every member at once — and nothing custom was needed to make that work, because each member's feed carries <blyg:manifest>, so plain OPML resolves to the blyg upgrade for free (§11, #13, #17). The members list a group construct would have introduced already exists, in a format other people's tooling reads, published as a deliberate curated act with no completeness claim.

Optionally a house blyg. The house origin can be a blyg of its own, and if the house has an editorial voice it should be: editorials, announcements, curated hoppers of member work (§13.5), stubs that actually respond to members' pieces. The house is then a publisher among publishers, with its own accountability, rather than a directory pretending to be a publication.

Consequences worth naming before choosing this shape:

  • Each member withdraws their own items (spec §9) and owns their own pins (spec §8).
  • Each member's author is their own assertion at their own origin.
  • Cross-member quoting is ordinary cross-client transclusion (#26) and sends real Webmentions (§15). The house's internal conversation is publicly checkable exactly like anybody else's — a feature, not overhead.
  • Members cannot speak in each other's name. A mention verifies only if the source's item document was fetched from exactly {origin}items/{id}.json for the origin it declares (§15.4 step 2, decision #61). So a document served under house.example/alice/ that claims to be house.example/bob/ fails, and Bob's items are safe from Alice even though they share a host. This was not true when this note was first written: the 0.3 text compared scheme, host and port only, and Aneesh Sathe's conformance model found the hole in exactly this shape (finding F1). The eighth revision of the spec closed it on 2026-10-06, and blygger-studio 0.32.2 implements it. A receiver still running older code keeps the hole until it upgrades, so a house on a shared host should run current clients for all its members.
  • The cost is real: N deploys, N polling crons, N sets of pin promises, N archives to keep serving forever. Withdrawal being permanent and pins being irrevocable means an origin is a long commitment, and this shape makes N of them.

4. Shape B — one origin with bylines

The masthead, specified since #11: one origin, one feed, one archive index, one manifest, and per-item author bylines. The feed invariant is single-publisher, never single-author (§5.5), precisely so that this shape is conformant without a social layer.

Consequences, which are the mirror image of shape A's:

  • The publisher can withdraw anyone's item and owns every pin. One party is accountable for everything at that origin, which is the point.
  • No member has a citation surface of their own. A stub of Alice's piece is a stub of the house's item, carrying Alice's byline as passed-through data.
  • One subscription, one blogroll, one editorial identity, one deploy, one cron.
  • A member's items cannot leave with them. Ids are origin-scoped (#2, §5.1); the same words at a new origin are a new item, or a fork from a pin (§5.6).

5. The test: who can withdraw

#36 names one question to choose between the shapes, and it is not "how many people are there":

Can this person's accountability be someone else's?

Operationally: who gets to withdraw, and who owns the pins. Withdrawal is the protocol's only exit and it is permanent (#8); a pin is an irrevocable promise to serve one version forever. Those two are the whole of what an origin is on the hook for. A member whose retractions must be their own decision, and whose citations must survive a falling-out with the house, needs their own origin. A member who is content for the house to answer for their work does not.

This cuts across the intuitive axis. A five-person magazine with a real editor is one origin — the editor withdrawing a piece is the editorial relationship working. Two friends who trust each other completely but publish under professionally distinct names need two origins, because the thing they need separate is not affection but accountability.

The choice is less fateful than it looks, because of #35. Practice for identity (proposed in docs/proposals/identity-practice-proposal.md) is that a person is a URL they control, provable by a reciprocal link or a signature. A byline carrying a verified home URL is recognisable after a move from shape B to shape A, which is otherwise impossible: §5.5 forbids treating equal author values at different origins as the same entity, and a verified claim is the only thing that lifts it. Be precise about what is portable, because this is where an implementer will over-promise: the person is portable, the items are not. Moving means new ids at a new origin, with lineage expressed as forks from pins if the old origin pinned anything.

6. Why content-free stubbing is an anti-pattern

The aggregator-by-stub proposal is the interesting half, because the pipe it describes is byte-for-byte conformant. Every document it emits is a valid thread with a valid stub_of (§10.6). Every mention it sends passes structural verification (§15.4). No rule in the spec is broken. It is still wrong, for three independent reasons, and then there is the question of why the spec responds with prose instead of a MUST NOT.

6.1 The marker is the one claim nothing can check

stub_of is the protocol's only machine-readable assertion that this is a response to that. §10.6 rule 2 makes readers rely on the marker and never on body inspection — deliberately, because inspecting a body to decide whether it is a response would require the protocol to read prose, and it would let a reader overrule an author about what they wrote.

That design puts the marker's entire value in its honesty. Structural verification does not help: §15.4 checks that the source document really names the target at the origin it claims — it proves the relation exists, never that the relation means anything. A pipe satisfies it perfectly. So a stub emitted with nothing to say is not a weak response; it is a false statement in the one field where the protocol has no defence but truthfulness.

6.2 It floods the only scarce inbound signal there is

The protocol has no follower list, no follower count, no metrics, at any level, ever (#12, #13, §11). A publisher's entire inbound signal is verified mentions (§15.5) — and #41 identifies it as the strongest discovery signal available, because someone who responded to you demonstrably read you.

That signal is scarce by construction, which is what makes it informative. Pipe-generated stubs are indistinguishable from real ones at the receiver — the receiver sees a valid thread with a valid marker — so they degrade the signal to noise with no filter available, and the noise is loudest for exactly the publishers a group aggregator would target.

This is the trackback failure reproduced inside the protocol. Trackback died of unverified spam, and the protocol answered it with structural verification (#13). Verification defeats the impostor, who claims a relation that isn't in the document. It does nothing about the relay, whose relation is genuinely there and genuinely empty.

6.3 It reprices re-emission to zero, which §13.5 forbids by cost

§13.5's ban on re-emitting imported items has two halves with two different enforcement mechanisms. The mechanical half — imported items MUST NOT appear in your feed, index, or item documents — is enforced by the blyg:id rollup contract and the single-publisher invariant: violating it breaks readers, so it holds itself up. The editorial half — "speech about someone else's content costs editorial work" (#12) — is enforced by nothing but the cost. Write an item; that is the price.

Automating stub creation sets that price to zero. The result is the naked retweet that #12 refused, rebuilt out of legal parts: content appears on your feed under your origin with no editorial act anywhere in the loop. Nothing mechanical catches it, because there is nothing mechanically different to catch.

6.4 The line is content-free, not automated, and not non-human

This must be said explicitly, because the obvious summary of sections 6.1–6.3 above is "don't let robots stub", and that summary is wrong. #38 rules the protocol agent-agnostic at every level: an agent is a valid author (§5.5), generated prose is disclosed by generated (§5.7), and invariant 3 constrains the reader side and the wire, never who writes.

An agent that reads each member item and answers it under its own byline, disclosed as generated, is stubbing legitimately, however many stubs that is — a critic, not a planet. Many mentions from one busy respondent are fine; each one says a real thing about a real item (#44 makes the same point for generation sources). What is illegitimate is a response with nothing in it, whoever or whatever emits it. A human who copy-pastes "interesting" under fifty transclusions a day has built the same pipe by hand.

6.5 Why this is a warning sentence and not a MUST NOT

The natural instinct is to forbid it: "a stub MUST carry editorial content." That rule cannot be written, for two reasons.

It is not checkable. "Has something to say" has no machine test. A word count is trivially defeated and would fail legitimate one-line responses. A similarity check against the target is an editorial judgement the protocol has no business making. A MUST that nothing can test is worse than no MUST: it teaches implementers that this spec's requirements are aspirational, which devalues the ones that are real. #48's conformance partition depends on MUST-clauses being exactly the set a checker fails on.

The constructs are identical. A pipe's output and a critic's output differ only in what the prose says. There is no field, count, flag, or shape that separates them — which is the same reason #38 refuses an "I am an agent" flag (a spammer would not set it) and #34 refuses a maintenance declaration (the software that would have to say it is the software nobody updates).

So the spec does the only thing available: it says plainly, in §10.6, that a stub emitted without a response is a misuse, names the honest alternative in the same breath, and leaves it as reputation rather than validation. A protocol that cannot enforce a norm can still refuse to pretend the norm doesn't exist.

7. The honest aggregator, which needs nothing new

Everything the "one place to follow a group" request actually wants is already built:

  1. Curation display (§13.5). Import the members, display their items publicly with source attribution and links to the origin. Publicity is a property of the displayed list, never of an imported item — there is no per-item public toggle and there will not be, because that is the naked retweet again.
  2. A blogroll of the members (§11). One OPML import subscribes a reader to every member. This is the aggregator's most valuable output: it makes itself unnecessary for readers who have a blyg-aware client, which is the correct relationship for a directory to have with the medium it indexes.
  3. Optionally a plain RSS digest, outside the blyg surface (§13.5). Excerpts and links to origin permalinks, no blyg: namespace, not feed.xml. Its consumers are L0 readers who need nothing from the protocol, and keeping it outside the surface is what stops it being re-emission.
  4. Optionally its own blyg, if it has an editorial voice — see section 3 above. A digest is plumbing; an editorial voice is a publisher, and a publisher's stubs are real responses.

No re-emission at any step, and no stubs on the members' behalf.

8. Rejected designs

Recorded because each will be re-proposed.

  1. A group or space construct — a members array in the manifest, a group key, a shared parent identity. Rejected three ways: it is a follower-list-shaped surface and the first place a count could attach (#12/#13, and #47 refused a per-item responses list for the same reason); it makes something below the origin addressable, which #11 forbids permanently; and it duplicates the blogroll, which is already the members list, already curated, already read by other people's tooling.
  2. user@server or any two-level addressing. Closed at #11: DNS is the namespace. Mount independence is what makes the second level unnecessary — a path is a namespace, and house.example/alice/ is a first-class origin with no new grammar.
  3. Per-author feeds carved out of one origin (feed.xml?author=alice). The feed URL is bound up with subscription identity (§12.2), and the manifest's feed value is what locates it (#51). A per-member feed with its own manifest is not a variant of shape B; it is shape A, with the deployment cost hidden until the first withdrawal.
  4. Letting an aggregator re-emit member items. Not a policy call but a collision: blyg:id rollup plus the single-publisher invariant means the copy and the original present as one item with two publishers (§13.5).
  5. A digest construct on the wire. Unnecessary — the digest's audience is plain RSS readers, so it needs no blyg vocabulary, and giving it some would put a second lossy notification plane inside a surface that already has one.
  6. The aggregator-by-stub pipe, per section 6 above.

9. What stands

  • No new construct for groups, at any level. Two supported shapes: N origins under one host with a house blogroll (and optionally a house blyg), or one origin with per-item bylines.
  • The test is who can withdraw — accountability, not headcount. #35's verified home URL is what keeps a byline recognisable if the answer changes later; the person moves, the items do not.
  • Members are studio-side, as #31's scoped tokens. There are no author folders on the wire: one origin, one feed, one index, and the byline is the distinction.
  • A stub emitted without a response is a misuse — false in the one field nothing can verify, a flood of the only scarce inbound signal, and a repricing of re-emission to zero. Said as a warning in §10.6 rather than a rule, because no rule can distinguish the pipe from the critic, and an unenforceable MUST would cost more than it bought.
  • The honest aggregator is §13.5 plus §11, plus a plain RSS digest outside the surface if it wants one. This is locked decision #36; relitigating it starts from this note.

This note's canonical text is at blygger.org/notes/tn-3/, and its source is docs/notes/tn-3-groups-and-aggregation.md in blygger-spec. The page there is what the spec cites. To comment, respond to this item from your own blyg.

read the thread →

Created: Oct 7, 2026

thread

TN-1 — Versioning stays a bare counter: semver, editions, and the pin pattern

Technical note · non-normative · session 12, 2026-08-10 (Fable + Venkat). Decision record for locked decision #19. Technical notes record design reasoning — especially rejected designs — alongside the normative spec; they constrain nothing and are citable rationale, not protocol.

1. The question

Item versions are a bare integer counter: version increments by exactly 1 per publish event (spec §5.2). Venkat proposed switching to semantic versioning so that version structure could carry an author-asserted significance signal — the motivating use case being client-side auto-pinning heuristics ("a node might declare a rule that every major version change be auto-pinned"), with the auto-pinning logic itself explicitly outside protocol scope.

The underlying need is real: a machine-readable way for an author to mark a publish event as significant, which client features can key off. The question is whether version structure is the right carrier. Two designs were considered and both rejected; the reasoning is worth keeping because the question will recur.

2. Why not semantic versioning

Three independent arguments, each sufficient:

  1. The counter's rigidity is load-bearing. "Increments by exactly 1" means a version number alone tells an importer exactly how many publish events it missed, and any decrease is unambiguously a history rewrite — the no-silent-regression watermark (decision #18) leans directly on this. Under semver, "+1 exactly" becomes "some component incremented": is 2.3 → 4.0 a gap? Is 2.0 → 1.9.1 a regression or intent? Every comparison becomes structured parsing, and origin violations stop being crisply detectable.
  2. The counter is wire-permanent surface. It rides in the GUID scheme (blyg:{id}:v{n}), pin URLs (items/{id}/v{n}.json), transclusions provenance, and the reserved ![[id@vN]] and forked_from shapes (decisions #14/#16). With two live nodes deployed, restructuring it is the protocol's first breaking wire migration — a cost that only grows.
  3. Semver encodes the wrong semantics. Its parts are API compatibility claims — patch-vs-minor is a statement about callers not breaking. Prose has no callers. Whatever significance structure writing has, it is not three-valued compatibility.

3. The edition counter-proposal (recorded, also rejected)

An intermediate design was drafted: keep version untouched and add an optional author-asserted "edition" integer (default 1, monotonically non-decreasing, bumped as a deliberate publish-time act). Publishing-native ("second edition"), additive, zero wire breakage; auto-pin heuristics key off edition bumps; a semver-looking display ({edition}.{rev}) derivable as pure presentation.

Rejected by Venkat — not on cost grounds (the cost is near zero) but on design-intent grounds, which is the actual content of this note:

4. The pin pattern is the significance primitive

The protocol already has a construct for "this state of this work matters": the pin — an irrevocable promise to serve one exact version forever (spec §8). The design intent is that publishers think consciously in pins, and a parallel significance lane would obscure that:

  • An edition bump is cheap talk; a pin is a costly signal. Marking a version "major" costs nothing and promises nothing. A pin costs an irrevocable hosting commitment. The protocol prefers the significance signal an author must back with a promise — that asymmetry is what makes the signal honest, and it would be exactly the asymmetry a free-floating significance field lets authors route around.
  • Version-structure significance is publishing skeuomorphism. Editions and major versions are conventions imported from books and software — cosmetic structure over what is, in this medium, a single living stream of states with deliberate frozen citations. The medium's own native gesture is the pin; dressing the stream up in edition numbers teaches publishers the wrong mental model.
  • The motivating feature doesn't need the field. "Auto-pin on major bump" dissolves into pin-suggestion UX: a studio may prompt, nudge, batch, or apply any local rule it likes for proposing pins — studio sugar, zero protocol bytes. This is the standing pattern's next application: AI, identity, and editorial convenience are never in the protocol; neither is significance markup. What reaches the wire is the pin itself.

Human-readable significance keeps its existing home: the changelog note (free text, per publish event). Machine-readable significance is the pin.

5. What stands

  • version remains a bare positive integer, +1 per publish event — the protocol's ordering primitive, unchanged everywhere it appears.
  • No semver, no edition field, no significance markup on the wire, at any level. This is locked decision #19; relitigating it starts from this note.
  • Clients remain free to build any pinning convenience (prompts, local rules, batch review) on studio-side state — the protocol surface they produce is ordinary deliberate pins.

This note's canonical text is at blygger.org/notes/tn-1/, and its source is docs/notes/tn-1-versioning-and-pins.md in blygger-spec. The page there is what the spec cites. To comment, respond to this item from your own blyg.

read the thread →

Created: Oct 7, 2026