A namespace for things defined in FEPs

Thankfully @aschrijver already described the underlying problem in

Can we quickly solve this problem at least for Concepts which are already defined in FEPs?
All of redaktor’s architecture is based on JSON-LD.
This means as concrete example that if we use a FEP-400e: Publicly-appendable ActivityPub collections we need any way to identify it, for example asExt:PublicAppendable
as in "type": ["Collection", "asExt:PublicAppendable"]

Yet, 3 properties had made it in the Original as: namespace after it was specified as text.
These are as:manuallyApprovesFollowers , as:sensitive and as:movedTo .

Other properties are in vendor namespaces like toot:featured or
focalPoint: {'@container': '@list', '@id': 'toot:focalPoint' }

But how to deal with Classes / Types as in FEPs?

Arnold did post the formal concept/diagram of the SIOC vocabulary, so I am posting the diagram how this is used in the @redaktor.me architecture.
I left out a few things to not make it not to confusing like sioc:Site/as:Page which is very complex in redaktor CMS.
Showing only differences to the original, mainly:

  • In redaktor a “User“ is not the “Actor”, a “User” can/could have multiple “Actor”
  • A “Topic” can be an “Actor”

(sorry, if I use the svg version, no text is shown, even w unspecified fonts, also reflexive rel not shown, but e.g. a Group can be member of a Group)
view in Live Editor / markdown source

In this example, we had no namespace for the concept of the Collection FEP-400e: Publicly-appendable ActivityPub collections

It should really be the same in all different ActivityPub implementations.
We handle it in the International Press Telecommunications Council by just having the IPTC core namespace and the extension namespace denoted by Ext as for example in Adobe Iptc4xmpExt
Maybe we can do the same here?
Basically, the only thing needed is a namespace and URL we need to specify permanently.


https://w3id.org/asExt/ (automatically done w. SkoHub)
preferred namespace prefix

and simply published with SKOS and https://skohub.io from the FEP repos …
This would mean to just follow the steps described in Presenting the SkoHub Vocabs Prototype | Skohub Blog

The turtle file could e.g. quickly describe the FEP process (together with links/references) as :n00 and then describe

:n001 a skos:Concept ;
    skos:broader :n00 ;
    skos:inScheme :scheme ;
    skos:notation "001",
        "0011" ;
    skos:prefLabel "Öffentlich-anhängbare  ActivityPub Collections"@de,
        "Publicly-appendable ActivityPub collections"@en ;
    skos:definition "FEP-400e",
    skos:scopeNote "Collection owned by someone that other people can contribute to. "@en .
    skos:note "see https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-400e.md"
1 Like

There are 4 already, with the fourth being as:alsoKnownAs, added to be consistent to DID:Core (see PR).

In addition to what you mention, I think we should avoid vendor-specific namespaces, unless well… they are purely relating to vendor-specific extensions. Right now the way these namespaces would proliferate would make little sense to me. I think a grouping into app-independent domains is necessary besides having an asExt for core vocabulary extensions, like e.g. ‘video’, ‘podcast’, ‘blog’, etc.

Naming of namespaces should be done carefully so they indicate a more generic domain, where different apps targeting that same domain can propose extensions to the vocabulary if they intuitively fit there and a FEP is finalized for them.

Also I wonder if there should be some versioning scheme to asExt. What if these extensions become native part of a future AS 3.0? The asExt would then be effectively superceded.

As to naming of this namespace I would not abbreviate and maybe have e.g.

  • https://w3id.org/activitystreams/core/extension
  • https://w3id.org/activitystreams/2.0/core/extension (versioned?)

As to how domain-specific namespaces might look like… euhh idk, maybe:

  • https://w3id.org/activitystreams/extension/video
  • https://w3id.org/activitystreams/extension/microblog (now mastodon toot)
  • https://w3id.org/activitystreams/extension/microblog/posts (alternative)

added to be consistent to DID

as in “DID not happen” cause of Googles and Apples power (aka “formal objection”) in W3C … :frowning:

I think we should avoid vendor-specific namespaces

This is the reason why I wrote it and propose to do it in the same way than we did in IPTC.
On the other hand any software should support the owl:sameAs definitions cause they are used already in specifications.

I think a grouping into app-independent domains is necessary besides having an asExt for core vocabulary extensions, like e.g. ‘video’, ‘podcast’, ‘blog’, etc.

I do not understand. Isn’t the FEP repo “app-independent”?
The https://w3id.org URL is just the Permalink, so if the repo location changes (e.g. in 100 years), the URL could be still working …

These are Object-Types and not concepts. We can really do already with ActivityPub.
The difference is that a concept specifies things which AP can do with them while Object-Types just describe the data structure of the type.

What if these extensions become native part of a future AS 3.0?

owl:deprecated and skos:changeNote are used for such things.

Can you specify which things in the diagram you mean by “vendor-specific namespaces”?

Most important is that in any ActivityPub or LD anything can have multiple type - the targeted app will choose the best (most narrow) type …
So, for example {"type": ["sioc:Usergroup", "redaktor:Instance"]} :
The sioc:Usergroup is a redaktor:Instance too because in system:redaktor some things might be different from other systems:
A user can use different clients, the instance can serve different clients and the instance is an Actor too.

I think that the skohub approach / workflow has lots of benefits for collaboratively publishing Vocabularies from a single repo and you can even follow …

[edit / addendum to anyone never heard of SKOS or skohub]
OWL and SKOS are the W3C recommendations.
The skohub.io people are powering a large portion of the infrastructure for german universities, e.g. the System where I find the books in uni libraries nearby, they know what they are doing - to learn about the benefits watch the short Demo Video or Conf Video

It is my fault as I should’ve been a bit clearer. First, those names I used were just random examples to indicate dividing into separate vocabularies (might also have used ‘fooDomain’ and ‘barDomain’), and second they are thus part of the namespaces ‘prefix part’ (don’t have the proper terminology, thought we’d just say ‘namespace’ for it).


  "@context": [
      "sc": "http://schema.org#",
      "video": "https://w3id.org/activitystreams/extension/video#",
      "framesPerSecond": {
        "@id": "video:framesPerSecond",
        "@type": "sc:Number"

  "id": "https://conf.tube/w/daJwZp7HhQFK5v3B9L89oY",
  "type": "Video",
  "framesPerSecond": 60

In the example above framesPerSecond is defined in the AS namespace for video-related (i.e. domain-specific) vocabulary extensions. Anyone developing for that same domain (e.g. Peertube, Owncast, Pixelfed when they add video capabilities) can propose new types and properties in this vocabulary.

Whereas, when looking at the current app-specific @context that PeerTube uses:

Peertube JSON-LD context (click to expand)

  "@context": [
      "RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
      "pt": "https://joinpeertube.org/ns#",
      "sc": "http://schema.org#",
      "Hashtag": "as:Hashtag",
      "uuid": "sc:identifier",
      "category": "sc:category",
      "licence": "sc:license",
      "subtitleLanguage": "sc:subtitleLanguage",
      "sensitive": "as:sensitive",
      "language": "sc:inLanguage",
      "isLiveBroadcast": "sc:isLiveBroadcast",
      "liveSaveReplay": {
        "@type": "sc:Boolean",
        "@id": "pt:liveSaveReplay"
      "permanentLive": {
        "@type": "sc:Boolean",
        "@id": "pt:permanentLive"
      "Infohash": "pt:Infohash",
      "Playlist": "pt:Playlist",
      "PlaylistElement": "pt:PlaylistElement",
      "originallyPublishedAt": "sc:datePublished",
      "views": {
        "@type": "sc:Number",
        "@id": "pt:views"
      "state": {
        "@type": "sc:Number",
        "@id": "pt:state"
      "size": {
        "@type": "sc:Number",
        "@id": "pt:size"
      "fps": {
        "@type": "sc:Number",
        "@id": "pt:fps"
      "startTimestamp": {
        "@type": "sc:Number",
        "@id": "pt:startTimestamp"
      "stopTimestamp": {
        "@type": "sc:Number",
        "@id": "pt:stopTimestamp"
      "position": {
        "@type": "sc:Number",
        "@id": "pt:position"
      "commentsEnabled": {
        "@type": "sc:Boolean",
        "@id": "pt:commentsEnabled"
      "downloadEnabled": {
        "@type": "sc:Boolean",
        "@id": "pt:downloadEnabled"
      "waitTranscoding": {
        "@type": "sc:Boolean",
        "@id": "pt:waitTranscoding"
      "support": {
        "@type": "sc:Text",
        "@id": "pt:support"
      "likes": {
        "@id": "as:likes",
        "@type": "@id"
      "dislikes": {
        "@id": "as:dislikes",
        "@type": "@id"
      "playlists": {
        "@id": "pt:playlists",
        "@type": "@id"
      "shares": {
        "@id": "as:shares",
        "@type": "@id"
      "comments": {
        "@id": "as:comments",
        "@type": "@id"

Then we see that ‘frames per second’ is defined in app-specific manner as pt:fps. And also we find the app-specific definition of pt:commentsEnabled. Both of these make no sense to exist in an app-specific vocabulary. In the first case, when e.g. Owncast wants to define ‘frames per second’ they shouldn’t have to refer to a PeerTube namespace to do so interoperably.

And in the second case is ‘comments enabled’, if you want to define it in a universal manner, something that doesn’t belong in the AS ‘video’ vocabulary. There are many more app / business domains where you want to add commenting functionality. This property might be part of the ‘core extension’ namespace, or even get its own ‘comments’ vocabulary.

Another vendor-specific extension right now are the toot properties that Mastodon defines .e.g.

  "toot": "http://joinmastodon.org/ns#",
  "featured": {
    "@id": "toot:featured",
    "@type": "@id"

Some considerations to make here are:

  1. Keep as-is given that this is already such widely adopted extension?
  2. Define corresponding / equivalent vocab at w3id.org and recommend its use?
  3. Define at w3id.org and also provide a better domain separation?

On point 3) if you look at featured you can see that featuring something is not restricted to toots, so it might be defined in a more generic way, idk maybe in a ‘public relations’ vocabulary.

Other than that, as you rightfully say, best-practice is to use well-defined (general-purpose) vocabularies / ontologies if they exist, so starting with having a peek into schema.org if something already exists makes a lot of sense (see also PeerTube @context above).

I mention ‘general-purpose’ vocabularies. If for ‘toot’ vocab we’d choose option 1) then it’d be considered a de-facto general-purpose vocab. Other vocabularies that are meant to be general-purpose may not be stable enough to be used as such. Example is ForgeFed, where the project has stalled and its status is unclear. The forgefed site may suddenly disappear. For Podcasting a healthy initiative looks to be well underway with podcastindex.org and then using that is a logical choice.

(Btw, note that in the case of ForgeFed there are other thoughts as to how to move forward. “Code forges” are a particular type of application, but they do not represent the business domains well, and these domains are the reason why one chooses a code forge tool. Wrt business domains you can think of ‘Revision control’, ‘Issue tracking’, ‘Project management’, etc. On Discuss Social Coding I have therefore started an initiative to consider the entirety of software development, and defined the “Free Software Development Lifecycle” or FSDL as the top-level domain)

Agreed. This is mentioned in several places on this forum and elsewhere, and something that most implementations do not support yet, but is truly part of the open standards, so time to encourage projects to take that into account. I would say that the discussion about this warrants a new topic? As this is more about method on how you’d combine objects and properties from different namespaces together in your designs. Idk.

The standards do recommend to derive from a primitive type, whenever feasible. In the example above that might look like:

{"type": ["Group", "sioc:Usergroup", "redaktor:Instance"]}

Unless, of course, a sioc:Usergroup is in no way derivative of a Group. When another app encounters this object type it either falls back to Group, or - if there is no fallback - ignores the object and/or activity that contains it (because Create{UnknownType} doesn’t make sense). The recommended practice is to have the AS ‘primitive’ type come first in the type array.

Note btw that it looks like type arrays can be used both for inheritance and for composition. I don’t know if that’s confusing. Example (fictionary):

{"type": ["Group", "sociocracy:Circle", "sociocracy:Governed"]}

In this example:

  • Circle is_a Group (inheritance relationship, Circle is a sub-type of Group)
  • Circle has Governance (interface / aspect composition, Circle has Governed behavior attached to it)

To bring this back the namespace discussion, here you see the value of sub-domain division. Some apps (not sure, but maybe #software:smithereen?) are considering to add support for Circles. If you only had one extension namespace e.g. asExt, then you’d have to adjust the names to be e.g. Circle (or SocialCircle, whatever) and SociocracyCircle. This can lead to some really unintuitive names, which we can also see when looking at schema.org.

I see where you’re going with that so this is slightly off topic, but we just use a Collection for circles. They’re literally mailing lists.

1 Like

Ok, now understood.
Let’s stick to your example and avoid a few misconceptions, so I’m adding my “assuptions”:

  • We want to extend the type "Video".
  • The Community voted for the FEP process to do so
  • One type Video can be extended by many FEP
  • Each implementation has a different "@context"

Your example would now put a “constraint” in the FEP-process saying
“The community has already voted how to use framesPerSecond in Video, either specify it as another name or use the available definition.”

To stick to this concrete example, I would then never use this extension.
My personal opinion would be that “framesPerSecond” should always come from the most authorative source. This is the camera which produced the Video. This camera (most modern cameras) but also modern Video Editing software will store it as Linked Data already in the property xmpDM:videoFrameRate.
These things coming from devices are from the exif, IPTC and XMP namespaces.

short history: The old namespaces were for metadata for image coming from device (exif) and editor (iptc), both had different standards bodies and for Video it was even more. The “Extensible Metadata Platform (aka ‘xmp’) Consortium” formed. By the time they worked closely together with W3C LD working groups but with own specs.
Each namespace is well documented but I am recommending the Overview Page first.

So, there is mostly no need by the user to specify it then, except choosing to change the fps with your software.
The “industry” choosed to use xmpDM and produces the devices, which means, cameras may write fps in e.g. native EBML/matroska or mp4 metadata and in LD it ends in xmpDM:videoFrameRate
This is the only source from devices.
The framerate is a metadata-piece which has to be in every video.
Technically you can destroy the XMP bag and the file is fine (bag = nicer word in IPTC/XMP for LD-Container).
But this will not delete the info in the file. Things like width, height, codec, framerate are needed to make a video a video. If you delete these bits, you destroy the video-file.
But otherwise we should give user control over metadata as described in would-media-captioning-make-a-good-fep
After writing I will go on with GitHub - redaktor/mediaproxy: A proxy to cache media and deliver ActivityPub markup -
this is the building block like in mastodon or peertube to cache media from different sources or to resize, stream etc. it. But it can do a ton of things more cause it has content-negotiation. Had described it for Will here ← this example is for Image but we added the Video part meanwhile and cause Framerate is mandatory it would be in xmpDM:videoFrameRate cause as you see in the source we parse the following filetypes bit by bit mp4, mkv, mov, 3gpp, 3gpp2, enc-isoff-generic, jp2, mj2, quicktime, vnd.dvb.file, webm, 'x-m4a' and 'x-m4v', 'x-matroska', the few new Apple formats are in work, so we have fps from every favourite webvideo type but as it is used by the player.

Anyway, I would more prefer to have an option like
{"type": ["Video", "asExt:FEPxxx1Video", "asExt:FEPxxx2Video"]}
so that FEPs can live independently.

Which do not support it?
If they do not support multiple type, it is not ActivityPub at all.
If they do not support some of the type, it is fine as long the ActivityPub type(s) are supported. But I choosed the example cause if I understood correctly in “Common Domain”, you proposed to use sioc: to describe our systems.

For things that do exist already, I use existing namespaces, like schema.org. For my own extensions, especially the ones that replicate some VK-specific functionality, I define them in my own (https://smithereen.software/ns#) namespace.

But then, for private/closed groups, I find myself using my namespace a lot. There’s a property that defines the access type of the group, and it’s called sm:accessType (can be open, closed, private). There’s an endpoint that gives you a token to fetch objects from other instances, and it’s called sm:actorToken. I also use sm:TentativeJoin activity type for my events.

But then, also, a closed group has as:manuallyApprovesFollowers set to true, and in general works like a Mastodon user that manually approves followers. And you can’t even get the actor of a private group without being invited to it.

But what is the type for the Public Appendable Collection described in FEP-400e ?

The scope is https://www.w3.org/ns/activitystreams#Public and you described properties from https://smithereen.software/ns# with sm
so, can we have a type?
{"type": ["Collection", "sm:PublicAppendable"]}

fwiw it’s more like “sm:MembersAppendable”.

We actually do need to express some permission metadata, however object types are not permissions and we probably shouldn’t confuse the two, because it doesn’t scale. We can express very rich permissions structures. For example, “Harry (not-moderated) and Meghan (moderated), but not William or Kate can append to this collection until after the 3rd of May, whilst Elizabeth can append to it without restriction”.

I’m merely trying to avoid painting oneself into a corner.

@grishka Also I would just like to give an answer to people asking how machines should refer to it.
So, meanwhile you said, ns is https://smithereen.software/ns# with sm.

And it is a specialised type of Collection. like in examples of the specification
But there is no name specified yet.
Just in the headline of the FEP “PublicAppendable”

So: https://smithereen.software/ns#PublicAppendable ?

PS: Tue meeting was supernice, there is another meeting today.

Agreed, likely starting with having a peek at schema.org as most authoritative …

Best-practice: Use the most authoritative ontologies to define new types and properties in FEP specifications.

  • But there are 1,000’s of ontologies and for common AS/AP interop they likely not be fully supported, but subsets are.

I am really wondering how to make an intuitive mechanism for FEP extensions, and one that places as low barrier on any dev to follow it.

  • A FEP is a clear specification document, and should follow a consistent template to guide implementers along.
    • FEP explains in words, examples, possibly diagrams both the message formats and heuristics (business logic) of an extension.
    • FEP must be accompanied by a JSON-LD @context document for any additional properties and/or types it defines.

The example of @Sebastian contains additional Video types to define XMP/IPTC metadata, and @grishka mentions app-specific extensions where some of them may be candidates to be standardized in a FEP (but maybe not all of them).

That wouldn’t be intuitive to me if I received such message, as the additional types are non-descriptive. I’d have to go to the FEP website and look up what they are about. If you want to know what FEP’s are applied, then that could be in the app-specific @context of the message.

(Note: In the following I’m just speculating on the concepts as I lack the experience, so it may not be proper way forward)

If the FEP only specified additional properties it might look like this:

  "@context": {
    "sc": "http://schema.org#",
    "xmpSubset": "https://w3id.org/activitystreams/extension/fep-xxx1.jsonld",
    "iptcSubset": "https://w3id.org/activitystreams/extension/fep-xxx2.jsonld",
    "videoFrameRate": {
      "@id": "xmpSubset:videoFrameRate",
      "@type": "sc:Number"
  "type": "Video",
  "id": "...",
  "url", "...",
  "videoFrameRate": 60,

If the FEP defined additional types it may look like this (with more intuitive naming):

  "@context": {
    "sc": "http://schema.org#",
    "videoMetadata": "https://w3id.org/activitystreams/extension/fep-xxx3.jsonld",
  "type": ["Video", "videoMetadata:XMPBasic", "myApp:FancyMetadata"],
  "id": "...",
  "url", "...",
  "metadata": {
    "videoFrameRate": 60,

There’s many different ways that this could be designed, and that’s something to get agreement on in the course of FEP standardization process. Things may be sliced differently, e.g.

  • A FEP that defines metadata container on any as:Object
  • A FEP defining as:Video metadata conforming to a minimum profile for added metadata
  • A range of FEP’s adding very specific metadata for specialized purposes

So in the @context you can find FEP url’s. If an implementer is using JSON then they can navigate to the URL in their browser to find the spec documentation, and if using JSON-LD they find a machine-readable context as well.

(Note that in the above examples you could also refer directly to the full XMP ontology, and use anything you want from that. That might however imho lead to too much diversity and too little common ground for interoperability among fedi apps. Hence the ‘common subsets’ defined in FEP’s)

There is really a misconception.

But there are 1,000’s of ontologies

Yes, but your software specifies whith for example exactMatch what has the same meaning or what is related or will be transitioned …

These links do not have to be descriptive. We would loose all the worlds languages then.
They are not meant for humans but for machines.
A machine looks up underlying RDF, OWL, SKOS descriptions and exactly knows what it derives from. If you use skohub it is already converted to a nice JSON LD you can work with internally. Then it fetches (mostly from cache) the description in your language for humans. The skohub videos explain this as well.
This is the way which e.g. my government and the EU does it or the library system here and if you have a look at the US Library of Congress, I would also call the URL semi-descriptive,
I mean, would a human know that http://id.loc.gov/vocabulary/relators/sht means ‘Supporting Host’ in the english language?

So in the @context you can find FEP url’s

The @context is only meant to shorten things, this does not help at all here.
Example videoFrameRate
(should be original xmpDM:videoFrameRate which cameras or convert-software writes – not humans) …
It is just the same to write "http://ns.adobe.com/xmp/1.0/DynamicMedia/videoFrameRate": 60

But my one and only question:
FEPs are .md documents - what is the URL for the Collection type FEP-400e PublicAppendable?

I disagree here. Names that are both human and machine readable are preferable, imho. Machines need very strict formats and don’t care about friendly names. A human is helped with at least some context if they see e.g. a code snippet in documention.

(If only machines mattered there wouldn’t be a need to have as:Like and as:Video, and we might have as:Cv75xR and as:T893hV instead).

Don’t understand what you mean by ‘losing all the worlds languages’. In ActivityStreams spec the ontology names are English as well, but the content can be any language. And a custom ontology may still be in a different language.

You are further with implementing Linked Data extensions to AS/AP than most other fedi devs, and besides you there are just a few others firmly on a Linked Data extensibility path. Some other devs still reject JSON-LD and plain JSON route.

It would be very good for onboarding and ‘paving the road’ to reaping the benefits of linked data, if there was more information and consensus about the extensibility mechanisms to use. More examples and documentation should be available, really, imho.

Maybe not, idk. Shouldn’t there be a way to find out what FEP’s a federated app is compliant to? This is likely not the best way to do so, I know. Another thing on the TODO-list for future fedi, maybe?

Ah yes, I forgot to add. Right now we just have FEP’s as markdown docs in a repo. They have the repo URL where you get the HTML for the spec. It might be better if they were published as html on a permalink, so that’s what I suggested in the above, where querying with a text/html contenttype would give you the spec docs.

Well, anyway, my software needs just any URL to use PublicAppendable Collection like as grishka said with the smithereen namespace {"type": ["Collection", " https://smithereen.software/ns#PublicAppendable"]} .

(or as macgirvin said rather https://smithereen.software/ns#MembersAppendable)
So, when redaktor sees a new Actor and wants to know in which Collection anybody can write.

PS: Any well known concept handles it this way, not only the cited LD sources Library of Congress, German National Library and Gov and EU but also the non-LD sources like wikidata, look at the page
https://www.wikidata.org/wiki/Q232562 this is an ugly number but if we would have named it /RuthGordon what would have happened if she changed her name?
There is sense behind this.
And then the URL tells you any details, if you look there, also what is the id in about 80 other sources …

No. I said it many times and I’ll say it again: we have to consider everything in real-world scenarios. I’m not interested in any of this theoretical fluff. I come up with a user experience first, and I build the protocol to accommodate that user experience. It is unacceptable to do it the other way around.

The fact that a given collection is publicly appendable doesn’t give your application any meaningful actionable information. The fact that the ID of this collection is in a sm:wall field of an actor, on the other hand, automatically means that:

  • This actor has a wall
  • This collection contains objects of type Note
  • This collection is publicly appendable
  • This collection is owned and managed by that actor

So I don’t see why this needs to be a thing unless you provide a concrete example of a real-world use-case where having a specialized type for a publicly-appendable collection would make a difference.

1 Like

Can you maybe point to the sm:wall definition in fep/fep-400e.md at main - fep - Codeberg.org ?
It is maybe just, we didn’t find it in the meeting …

Smithereen walls themselves are not part of the FEP. The FEP is a generalized construct for “a thing to which other people can add other things”.

To answer your question: that definition is in FEDERATION.md in Smithereen repository.