FEP-9606: Using w3id.org/fep as a namespace for extension terms and for FEP documents


This is a discussion thread for the proposed FEP-9606: Using w3id.org/fep as a namespace for extension terms and for FEP documents. Please use this thread to discuss the proposed FEP and any potential problems or improvements that can be addressed.


In JSON-LD, @id is used to identify nodes. Each node obect should contain an @id, which MUST be an IRI or a compact IRI (including blank node identifiers). It is considered best practice in the linked-data ecosystem to have such IRIs be HTTPS URIs that resolve to a definition of the term being used, and it is desirable to define such terms in a JSON-LD context file that is referenced by its IRI rather than having the full @context object embedded in every single document. ActivityStreams 2.0 and ActivityPub do this with the normative context and namespace provided at https://www.w3.org/ns/activitystreams, but this namespace is not generally open to extensions or to experimental terms.

This FEP therefore proposes using https://w3id.org/fep as a base IRI for the FEP process, allowing sub-namespaces for each FEP, and allowing certain terms to be promoted to a default context once proven broadly useful.


I’m reading through it and collecting my comments.

For example, we can consider the definition of “Public” addressing within ActivityPub, represented by the “Public” magic collection. When the normative ActivityStreams 2.0 context is applied, the IRI for this collection may be equivalently expressed as Public, as:Public, or https://www.w3.org/ns/activitystreams#Public.

This statement is untrue, but often made. Due to Public missing from https://www.w3.org/ns/activitystream, only as:Public expands to https://www.w3.org/ns/activitystream#Public. See Public is missing from https://www.w3.org/ns/activitystreams HTML page · Issue #531 · w3c/activitystreams · GitHub.

So please use another example.

		"exampleA": {
			"@id": "fep:9606/exampleA",
			"rdf:comment": "A term with some literal value (string, boolean, number)"

The rdf:comment is invalid. See

An expanded term definition MUST be a map composed of zero or more keys from @id, @reverse, @type, @language, @container, @context, @prefix, @propagate, or @protected. An expanded term definition SHOULD NOT contain any other keys.

in 9.15.1 Expanded term definition.

I would also like to see some rules on naming here. For example, nobody should introduce a term “Twitter” as we do not hold the trademark. I think I adapted from did-core.

Some more thoughts

I currently feel that it would be wise to require examples for each term in the new context and then run:

expanded = json_ld.expand(example)
recompacted = json_ld.compact(expanded, example["@context"]) 

assert recompacted == example

This would guarantee that the new context is valid. Furthermore, these examples will serve to explain the authors thinking. If one uses a build process for FEP documents, one can use this to include the examples in the FEP document.

I actually don’t have a strong preference of this FEP vs FEP-2e40: The FEP Vocabulary Extension Process. Now that I understand what is necessary. Of course, this means that all FEPs introducing Vocabulary terms need to be in the new folder format.

1 Like

that doesn’t sound right – the JSON-LD stuff works on the context document at https://www.w3.org/ns/activitystreams.jsonld which does contain Public being defined as as:Public which expands to the full https://www.w3.org/ns/activitystreams#Public

using the playground at JSON-LD Playground with the following document:

  "@context": "https://www.w3.org/ns/activitystreams",
  "to": "https://www.w3.org/ns/activitystreams#Public",
  "https://www.w3.org/ns/activitystreams#cc": "Public",
  "bcc": "Public",
  "https://www.w3.org/ns/activitystreams#bto": "https://www.w3.org/ns/activitystreams#Public"

if you look at the expanded form, you see that the IRI forms do not use the definition from context. they get parsed as a @value and not an @id in the expanded form. when they get compacted down against the same context, the as: is preserved but the actual definition is not. so for some reason, the reference JSON-LD parser being used on the playground does not equate a term with its IRI, neither the full IRI nor the compact IRI:

    "https://www.w3.org/ns/activitystreams#bto": [
        "@value": "https://www.w3.org/ns/activitystreams#Public"
    "https://www.w3.org/ns/activitystreams#bcc": [
        "@id": "Public"
    "https://www.w3.org/ns/activitystreams#cc": [
        "@value": "Public"
    "https://www.w3.org/ns/activitystreams#to": [
        "@id": "https://www.w3.org/ns/activitystreams#Public"
  "@context": "https://www.w3.org/ns/activitystreams",
  "bcc": "Public", // linked node
  "as:bto": "https://www.w3.org/ns/activitystreams#Public", // string literal
  "as:cc": "Public", // string literal
  "to": "as:Public" // linked node

the activitypub spec gives this hint:

5.6 Note:
Compacting an ActivityStreams object using the ActivityStreams JSON-LD context might result in https://www.w3.org/ns/activitystreams#Public being represented as simply Public or as:Public which are valid representations of the Public collection. Implementations which treat ActivityStreams objects as simply JSON rather than converting an incoming activity over to a local context using JSON-LD tooling should be aware of this and should be prepared to accept all three representations.

it’s not invalid, it’s just not recommended by the JSON-LD spec. i’m not super invested in having this included though, so i can take it out. i can replace this bit with a link to 9.15.1 Expanded Term Definitions in JSON-LD 1.1 in the absence of any other perspectives.

i’m unsure this is necessary. i understand the reasoning behind it, but it can be useful to use such terms. for example, in the discussion around payment links, it came up that you may want to differentiate between Paypal, Cashapp, etc. without parsing every single href for a prefix. i am not sure what legal requirements may surround something like this

not necessarily. we could set up the redirect rules for the old format as present in the commented out lines. having the new folder format just makes it easier.

https://www.w3.org/ns/activitystreams#Public is completely broken

Click on the link and you get an HTML documentation. It’s pretending to be a linked data vocabulary, but actually it’s not. It’s just a documentation page.

Public is in the context but not in the human readable docs.

AFAIK was all done without change control, so the spec, the “vocab”, and context have diverged, due to human error, there’s no new version number of the spec, and not at all clear how to fix it.

The elephant in the room is that Activity Streams 2.0 is not a linked data vocab, and never has been.

@melvincarvalho What would be necessary to make it a “linked data vocab”? Is the context document at https://www.w3.org/ns/activitystreams(.jsonld) not enough?

Creating a Linked Data vocabulary involves defining a set of terms and their relationships in a machine-readable format, typically using RDF. This allows you to create a structured and interoperable way to represent information on the web.

The important thing is that the vocab (aka ontology) is both human and machine readable. Right now the AS Vocab is only human readable.

You can test this on unix systems with the command:

rapper -g https://www.w3.org/ns/activitystreams

A note on:


This is a context, not a vocabulary. I think that is the thing that has confused everybody. They are different things. A context is syntactic sugar that goes in a JSON-LD file to help you save typing out of full urls and datatypes. Generally it can be inline, or linked.


rapper -g https://www.w3.org/ns/activitystreams.jsonld

Thows an error

Compare with:

rapper -g http://www.w3.org/2000/01/rdf-schema

This gives back a vocabulary

You are right, I was misremembering details. I’ll reply to the other stuff later, once I have the energy to properly review it.

after playing around a bit more, i managed to get this:

  "@context": "https://www.w3.org/ns/activitystreams",
  "https://www.w3.org/ns/activitystreams#to": {"id": "https://www.w3.org/ns/activitystreams#Public"},
  "cc": "https://www.w3.org/ns/activitystreams#Public"

to compact to this:

  "@context": "https://www.w3.org/ns/activitystreams",
  "cc": "as:Public",
  "to": "as:Public"

further expansion or compaction doesn’t result in Public no matter what i do, only as:Public.