How to write, query, update, and convert AMB resources — Nostr events of kind 30142, specified by NIP-AMB — in the Edufeed Educational Data Pool. The read side of the same data — fetching and rendering — is shown in the Educational Data Pool live demo.
Each educational resource is stored as a Nostr addressable event of kind 30142, implementing the
Allgemeines Metadatenprofil für Bildungsressourcen (AMB).
An event is uniquely identified by its three-part coordinate kind:pubkey:d-tag — the d tag typically holds the
canonical resource URL. Metadata is stored as flat Nostr tags using : as a nesting delimiter. The exact
on-the-wire mapping — which AMB property becomes which Nostr tag — is defined in
NIP-AMB,
the specification that defines kind 30142. "Kind 30142" and "NIP-AMB" always refer to the same event format —
the number is what goes over the wire, NIP-AMB is the document that specifies it.
What "addressable" means. Nostr defines four event-storage behaviours by kind range
(NIP-01):
regular events are kept indefinitely, replaceable events (kind 10000–19999)
keep only the latest per (kind, pubkey), and addressable events
(kind 30000–39999, sometimes called parameterized replaceable) keep only the latest per
(kind, pubkey, d-tag). Because the resource carries its own d identifier, one author can hold
arbitrarily many distinct kind 30142 resources, each independently replaceable in place — publishing the same
coordinate again overwrites the prior version rather than appending a duplicate. That stable coordinate is what makes a
resource referenceable: other events point at it with an a tag
("a", "30142:<pubkey>:<d-tag>") and it can be encoded as an
NIP-19
naddr for sharing. See the
NIP-01 "Kinds" section
for the authoritative range definitions.
| AMB property | Nostr tag(s) | Notes |
|---|---|---|
id |
["d", <uri>] |
Stable identifier, usually the content URL |
name |
["name", <title>] |
Human-readable title |
description |
["description", <text>] + content field |
Stored in both places; clients prefer content field |
keywords |
["t", <keyword>] (repeated) |
Nostr-native keyword tag |
about (concept) |
["about:id", <uri>]["about:prefLabel:<lang>", <label>]["about:type", "Concept"]
|
Repeated for each subject; multiple about-groups are co-indexed by tag order |
learningResourceType (concept) |
["learningResourceType:id", <uri>]["learningResourceType:prefLabel:<lang>", <label>]["learningResourceType:type", "Concept"]
|
Repeated for each type |
creator — with Nostr identity |
["p", <pubkey-hex>, <relay-hint>, "creator"] |
Only p tag is emitted; name resolved from kind:0 profile |
creator — external (no Nostr pubkey) |
["creator:name", <name>]["creator:id", <uri>] (optional, e.g. ORCID)["creator:type", "Person"|"Organization"]
|
Same structure for contributor, publisher |
isBasedOn / isPartOf / hasPart |
Nostr resource: ["a", "30142:<pubkey>:<d>", <relay>, <role>]External URI: ["isBasedOn:id", <uri>] etc.
|
Role is the property name, e.g. "isBasedOn" |
| External references ("see also") | ["r", <url>] (repeated) |
DOI, ISBN, OERSI source URL — Nostr-native NIP-24; no AMB equivalent on reverse conversion |
Extension namespaces — properties outside the AMB-core spec use an ext prefix so they coexist without collision:
ext:ekw:<facet>:<sub> — EKW vocabulary (e.g. ext:ekw:gradeLevel:id, ext:ekw:method:prefLabel:de).
<sub> is one of id, type, prefLabel:<lang>, name.
Free-text facets (ext:ekw:methodOther, ext:ekw:bibleReference) are bare key/value tags with no :sub suffix.
The full facet list and their vocabularies are in Section 5.
ext:<d-slug>:<facet>:<sub> — per-community metadata form fields where <d-slug>
is the d-tag of the kind 30168 form (colon-free). The form event itself is referenced via
["a", "30168:<pub>:<d>", <relay>, "form"].
Kind 30142 events are produced by any Nostr client that can sign on behalf of the author — whether it holds the private key directly or delegates to a remote signer (NIP-46). Signing is independent of where the event is published:
ext:ekw:*).
After signing, the event is published to the Edufeed AMB relay (wss://amb-relay.edufeed.org)
using standard Nostr EVENT messages. Anyone who can sign as the author can later publish
replacements or deletions for the same coordinate.
For a quick end-to-end check from the command line, nak (the Nostr army knife) builds, signs, and publishes a valid kind 30142 event in one call:
# Build, sign, and publish a kind 30142 event to the AMB relay
nak event -k 30142 \
-d "https://example.org/my-resource" \
-t "name=My Open Educational Resource" \
-t "about:id=http://w3id.org/kim/schulfaecher/s1055" \
-t "about:prefLabel:de=Religion" \
-t "learningResourceType:id=https://w3id.org/kim/hcrt/drill_and_practice" \
-t "learningResourceType:prefLabel:de=Übung" \
-t "t=Beispiel" \
-c "A short description of the resource." \
--sec nsec1... \
wss://amb-relay.edufeed.org
No — the canonical address of a resource is its coordinate 30142:<pubkey>:<d-tag>, which is
location-independent. The same signed event can be stored on any number of relays simultaneously.
The Edufeed AMB relay (wss://amb-relay.edufeed.org) is the primary index, but clients
are free to mirror or query elsewhere.
Query using standard NIP-01 filters:
// All AMB events (up to relay limit)
{"kinds": [30142]}
// Specific resource by coordinate
{"kinds": [30142], "authors": ["<pubkey-hex>"], "#d": ["<d-tag-value>"]}
// Filter by Nostr-native keyword tag
{"kinds": [30142], "#t": ["Gerechtigkeit"]}
// Filter by subject URI (AMB tag filter)
{"kinds": [30142], "#about:id": ["http://w3id.org/kim/schulfaecher/s1055"]}
// Filter by resource type URI
{"kinds": [30142], "#learningResourceType:id": ["https://w3id.org/kim/hcrt/drill_and_practice"]}
Tag filters only work for keys the relay indexes: all single-letter Nostr tags (d,
t, p, a, …) plus the AMB-core keys such as about:id and
learningResourceType:id. Values must match byte-for-byte (note the http:// scheme
above — it is whatever the producer stored, not necessarily https://). Extension namespaces
(ext:ekw:* and per-form ext:<slug>:*) are not indexed for filtering;
fetch a coarser set and refine client-side, or use the converter to read them out of the ext object.
Query using NIP-50 full-text search (supported by amb-relay.edufeed.org):
// Free-text search across name, description, keywords
{"kinds": [30142], "search": "evangelisch"}
// Field-specific filter via dot-notation
{"kinds": [30142], "search": "publisher.name:e-teaching.org"}
// Combined: free text + field filter
{"kinds": [30142], "search": "Frieden about.prefLabel.de:evangelisch"}
NIP-50 dot-notation covers AMB-core fields (name, description, publisher.name,
about.prefLabel.<lang>, …). Like the tag index, it does not currently reach ext.* facets.
Query from the command line with nak:
# All AMB events, newest first (limit 20)
nak req -k 30142 -l 20 wss://amb-relay.edufeed.org
# Filter by subject tag
nak req -k 30142 -t about:id=http://w3id.org/kim/schulfaecher/s1055 wss://amb-relay.edufeed.org
# NIP-50 full-text search
nak req -k 30142 --search "evangelisch" wss://amb-relay.edufeed.org
Kind 30142 is an addressable (parameterized replaceable) event. When a client publishes a new
event with the same (kind, pubkey, d-tag) triple, relays keep only the newest
created_at; older versions are superseded automatically. There is no explicit "patch" step —
the author simply re-publishes the full updated event.
Deletion uses NIP-09 (kind 5): the author publishes a deletion event referencing the
addressable coordinate as an a tag:
// NIP-09 deletion event
{
"kind": 5,
"tags": [
["a", "30142:<pubkey>:<d-tag-value>", "<relay-hint>"]
],
"content": "Resource removed"
}
Relays that honour NIP-09 will stop serving the referenced event. Clients that implement deletion-aware models will filter it from results automatically.
Classification uses SKOS-aligned controlled vocabularies. Every concept carries its vocabulary URI
(:id), a human-readable label (:prefLabel:<lang>), and the type marker
(:type = "Concept"). Multiple concepts in the same field are stored as repeated tag groups
(boundary on repeated :id).
| AMB field | Tag prefix | Example vocabulary |
|---|---|---|
about — subject |
about:id / about:prefLabel:de |
Schulfächer (Kim) |
learningResourceType |
learningResourceType:id / :prefLabel:de |
hcrt / new_lrt |
audience |
audience:id / :prefLabel:de |
LRMI audience vocab |
educationalLevel |
educationalLevel:id / :prefLabel:de |
Kim educationalLevel |
The EKW profile — named for the
Evangelische Kirche von Kurhessen-Waldeck (EKKW) —
adds domain-specific facets under the
ext:ekw:* namespace, plus three EKW-specific replacements for AMB-core vocabularies. All of these
vocabularies are published as Nostr concept schemes (kind 39737, individual concepts kind
39738) by VocabulOER
(npub16f5fut6…) and are browsable on Edufeed's vocabulary tool,
nocabs.edufeed.org. Concept :id
values on EKW events are therefore Nostr-native coordinates (nostr:39738:<vocab-pubkey>:<concept-d>),
not HTTP URIs.
| EKW field | Tag key(s) | Vocabulary |
|---|---|---|
gradeLevel |
ext:ekw:gradeLevel:id / :prefLabel:de / :type |
Klassenstufen |
schoolType |
ext:ekw:schoolType:id / :prefLabel:de / :type |
Schulart |
didacticConcept |
ext:ekw:didacticConcept:id / :prefLabel:de / :type |
Didaktisches Konzept |
method |
ext:ekw:method:id / :prefLabel:de / :type |
Methode |
methodOther |
ext:ekw:methodOther (bare value, repeated) |
Free text — author-supplied method not in the vocabulary |
bibleReference |
ext:ekw:bibleReference (bare value, repeated) |
Free text — e.g. Gen 1, Ps 104 |
about — subject (EKW-core) |
about:id / about:prefLabel:de |
EKW Fach |
learningResourceType (EKW-core) |
learningResourceType:id / :prefLabel:de |
EKW LRT |
keywords (EKW-core) |
t (Nostr-native, repeated) |
EKW Keywords |
Per-community metadata forms add further namespaces under ext:<form-d-slug>:* (kind 30168 forms),
referenced from the resource via ["a", "30168:<pub>:<d>", <relay>, "form"].
The amb-nostr-converter
library (the same tool powering the widget below) can reconstruct an AMB JSON document from any kind 30142 event.
It reverses the tag-flattening, re-groups concept arrays, maps p tags to
creator/contributor, maps a tags to relation objects, and surfaces
ext:* tags under a sibling ext object in the output.
Install it from the Edufeed npm registry and use the CLI (requires Node.js):
npm install amb-nostr-converter --registry=https://git.edufeed.org/api/packages/edufeed/npm/
amb-convert nostr:amb event.json
Or use the live widget below: pick a sample event — or one of the live EKW resources fetched in Section 7 — from the dropdown, and it loads into the left pane and converts automatically. Edit the JSON and click Nostr → AMB to re-run, or AMB → Nostr to go the other way.
Fetch a specific event from wss://amb-relay.edufeed.org and load it into the
converter above. Accepts a 64-character hex event id, an addressable
coordinate kind:pubkey:d-tag, or a
NIP-19
naddr, nevent, or note identifier (with or without a nostr: prefix).
The cards below are fetched live from wss://amb-relay.edufeed.org at page load — a direct Nostr
REQ for kind 30142 events authored by the EKW publisher
(npub1wak8hljj…), the same query any client would use. Each card shows the
resource title, description, and the ext:ekw:* facets it carries.
Everything in this guide is plain Nostr, so any Nostr library can read, write, and query kind 30142 events — no Edufeed-specific SDK is required. A few well-maintained options per language:
| Language | Library | Notes |
|---|---|---|
| JavaScript / TypeScript | Applesauce · nostr-tools | Applesauce is the high-level toolkit Edufeed itself uses (EventStore, models, EventFactory); nostr-tools covers low-level primitives (keys, NIP-19, relays). |
| AMB ↔ Nostr (JS/TS) | amb-nostr-converter | Edufeed's own converter between AMB JSON and kind 30142 — powers the widget in Section 6. |
| Go | go-nostr · khatru | go-nostr for clients; khatru for building relays. |
| Rust | rust-nostr (nostr-sdk) | High-level SDK; also the source of bindings for several other languages. |
| Python | nostr-sdk | Python bindings of rust-nostr. |
| PHP | nostr-php | Helper library — docs at nostr-php.dev. |
| CLI / shell | nak | The "Nostr army knife" used in the examples above — query, build, sign, and publish from the terminal. |
A broader, continuously updated catalogue of libraries and tools lives in awesome-nostr.
The converter widget (Section 6) runs entirely offline. The live feed (Section 7) opens one WebSocket to
wss://amb-relay.edufeed.org. Requires a browser that supports ES modules.