@@ -434,6 +434,37 @@ to these objects through their `tags` property. The exact way ActivityPub
434434implementations render these objects differs, but Mastodon and Misskey already
435435share a number of de facto conventions.
436436
437+ ### ` to ` , ` cc `
438+
439+ > [ !NOTE]
440+ > You can find more information in the [ Specifying an activity] document.
441+
442+ The objects described above can have ` to ` and ` cc ` properties that address
443+ their intended audience. These properties can also be used on other
444+ ActivityStreams objects, including activities.
445+ The ` to ` property identifies primary recipients, while ` cc ` identifies
446+ secondary recipients. To address multiple recipients, use the ` tos ` and ` ccs `
447+ properties.
448+
449+ ~~~~ typescript twoslash
450+ import { Note , PUBLIC_COLLECTION } from " @fedify/vocab" ;
451+ import { type Context } from " @fedify/fedify" ;
452+ const ctx = null as unknown as Context <void >;
453+ const identifier: string = " " ;
454+ // ---cut-before---
455+ new Note ({
456+ to: PUBLIC_COLLECTION ,
457+ cc: ctx .getFollowersUri (identifier ),
458+ // additional things...
459+ });
460+ ~~~~
461+
462+ This combination addresses the public collection as the primary audience and
463+ the actor's followers as the secondary audience. Mastodon uses this convention
464+ for public posts.
465+
466+ [ Specifying an activity ] : ./send.md#specifying-an-activity
467+
437468### ` Note ` : Short posts
438469
439470The ` Note ` type is the most common object type for short posts. In Mastodon,
@@ -729,3 +760,148 @@ For example, the above `Emoji` object is displayed like the following in
729760Mastodon:
730761
731762![ Screenshot: A rendered custom emoji in Mastodon] ( pragmatics/mastodon-emoji.png )
763+
764+ ### Replies
765+
766+ To reply to an object, create a ` Note ` whose ` replyTarget ` is the object being
767+ replied to, a ` Link ` to it, or its canonical URL. Fedify serializes
768+ ` replyTarget ` as the standard ActivityStreams ` inReplyTo ` property in JSON-LD.
769+
770+ For a public reply, address the public collection in ` to ` , and add the replying
771+ actor's followers and the parent object's author to ` cc ` . Also add a ` Mention `
772+ tag for the parent author, with a matching mention link in ` content ` :
773+
774+ ~~~~ typescript twoslash
775+ import type { Context } from " @fedify/fedify" ;
776+ import { Mention , Note , PUBLIC_COLLECTION } from " @fedify/vocab" ;
777+ const ctx = null as unknown as Context <void >;
778+ const identifier = " alice" ;
779+ const parentNote = new URL (" https://example.net/notes/123" );
780+ const parentAuthor = new URL (" https://example.net/users/bob" );
781+ // ---cut-before---
782+ new Note ({
783+ content: // [!code highlight]
784+ ' <p><a class="mention u-url" href="https://example.net/users/bob">' +
785+ " @bob@example.net</a> Thanks for sharing this!</p>" ,
786+ replyTarget: parentNote , // [!code highlight]
787+ to: PUBLIC_COLLECTION , // [!code highlight]
788+ ccs: [ // [!code highlight]
789+ ctx .getFollowersUri (identifier ),
790+ parentAuthor ,
791+ ],
792+ tags: [ // [!code highlight]
793+ new Mention ({
794+ href: parentAuthor ,
795+ name: " @bob@example.net" ,
796+ }),
797+ ],
798+ })
799+ ~~~~
800+
801+ The ` to ` and ` cc ` values are audience addresses, not inbox URLs. In particular,
802+ use the parent author's actor URL in ` cc ` , then deliver the ` Create ` activity to
803+ that actor through ` Context.sendActivity() ` . Give the enclosing ` Create `
804+ activity the same ` to ` and ` cc ` values as its ` Note ` object.
805+
806+ Mastodon uses the ` inReplyTo ` property to attach a reply to its parent thread.
807+ Addressing the parent author in ` cc ` delivers the reply to them, while a
808+ matching ` Mention ` tag creates a notification; neither establishes the thread
809+ relationship. Ensure the ` Mention.href ` , ` Mention.name ` , and the mention link
810+ in ` content ` all identify the same actor. For a non-public or direct reply, do
811+ not use ` PUBLIC_COLLECTION ` or the followers collection; address only the
812+ actors who should be able to see the conversation instead.
813+
814+ ### Allowing quotes
815+
816+ [ FEP-044f] defines consent-respecting quote posts. To allow anyone to quote a
817+ ` Note ` automatically, set its ` interactionPolicy.canQuote.automaticApproval `
818+ property to ` PUBLIC_COLLECTION ` :
819+
820+ ~~~~ typescript twoslash
821+ import { InteractionPolicy , InteractionRule , Note , PUBLIC_COLLECTION } from " @fedify/vocab" ;
822+ // ---cut-before---
823+ new Note ({
824+ content: " <p>Anyone may quote this note.</p>" ,
825+ interactionPolicy: new InteractionPolicy ({ // [!code highlight]
826+ canQuote: new InteractionRule ({ // [!code highlight]
827+ automaticApproval: PUBLIC_COLLECTION , // [!code highlight]
828+ }),
829+ }),
830+ })
831+ ~~~~
832+
833+ Advertising this policy improves interoperability with quote-aware
834+ implementations. Mastodon 4.4 verifies and displays remote FEP-044f quotes,
835+ and Mastodon 4.5 can author quotes and set automatic quote policies.
836+ [ Hackers' Pub] and [ Hollo] also support FEP-044f quote policies and the
837+ authorization flow.
838+
839+ > [ !NOTE]
840+ > Misskey's ` _misskey_quote ` property is a non-standard extension that only
841+ > identifies the quoted object's URL. FEP-044f's ` quote ` property represents
842+ > the same relationship, but its ` interactionPolicy.canQuote ` , ` QuoteRequest ` ,
843+ > and ` QuoteAuthorization ` terms also let implementations obtain, verify, and
844+ > revoke the original author's consent. Fedify's ` Note.quoteUrl ` supports the
845+ > legacy ` _misskey_quote ` , ` quoteUrl ` , and ` quoteUri ` properties for
846+ > compatibility, while ` Note.getQuote() ` and ` Note.quoteId ` represent FEP-044f's
847+ > ` quote ` property.
848+
849+ To require the author's approval instead, use ` manualApproval ` with the actors
850+ or collections that may request a quote. The policy advertises whether a quote
851+ is expected to be allowed, but it does not authorize a quote by itself. Under
852+ FEP-044f, the quoting actor sends a ` QuoteRequest ` ; after accepting it, the
853+ original author returns an ` Accept ` activity whose ` result ` is a
854+ ` QuoteAuthorization ` . The quote post then references that authorization.
855+
856+ See the [ interaction controls] documentation for the helpers that evaluate
857+ ` canQuote ` policies and create or verify quote authorizations.
858+
859+ [ FEP-044f ] : https://helge.codeberg.page/fep/fep/044f/
860+ [ Hackers' Pub ] : https://hackers.pub/
861+ [ Hollo ] : https://hollo.social/
862+ [ interaction controls ] : ./interaction-controls.md
863+
864+ ### Microformats
865+
866+ [ Microformats 2] is a convention for embedding machine-readable metadata in
867+ HTML with CSS class names. In federated posts, ` Note.content ` is HTML, so a
868+ receiving implementation cannot reliably infer whether an arbitrary link is an
869+ account mention, a hashtag, or an ordinary external link from its visible text
870+ alone. The classes provide that missing semantic information.
871+
872+ > [ !TIP]
873+ > Microformats are not required by ActivityPub, so a post remains valid without
874+ > them. Nevertheless, adding them is recommended for interoperability with
875+ > Mastodon and other implementations that recognize these conventions.
876+ > See Mastodon's [ Microformats specification] for the classes it supports.
877+
878+ For example, write a mention as an ` h-card ` containing a ` u-url ` link. The
879+ ` h-card ` identifies the linked text as a person or organization, and ` u-url `
880+ identifies the link as that account's profile permalink. Mastodon also uses
881+ its ` mention ` class to open the link as an in-app account mention instead of a
882+ generic URL:
883+
884+ ~~~~ html
885+ <p >Hello
886+ <span class =" h-card" >
887+ <a class =" u-url mention" href =" https://example.com/users/friend" >
888+ <span class =" p-name" >@friend@example.com</span >
889+ </a >
890+ </span >!
891+ </p >
892+ ~~~~
893+
894+ The ` mention ` class is a Mastodon-specific extension, not a Microformats class.
895+ Likewise, use ` class="hashtag" ` and ` rel="tag" ` on hashtag links so Mastodon
896+ can treat them as hashtags rather than ordinary links. These classes describe
897+ the HTML representation only; they do not replace ActivityPub metadata. Keep
898+ the corresponding ` Mention ` or ` Hashtag ` object in ` Note.tags ` , with the same
899+ URL and displayed name, so implementations can correctly process the post,
900+ including notifications and thread handling.
901+
902+ When generating ` content ` , preserve these classes through HTML sanitization.
903+ Removing them may leave the link clickable, but Mastodon-compatible clients can
904+ lose its mention or hashtag behavior.
905+
906+ [ Microformats 2 ] : https://microformats.io/
907+ [ Microformats specification ] : https://docs.joinmastodon.org/spec/microformats/
0 commit comments