Attention Nostr protocol
Attention currently uses:
- addressable kind
32009for single-subject trust, Neutral, distrust, and Delete; - addressable kind
32014for subject ratings (worth the reader's time); - replaceable kind
10011for verified NIP-39 X identity links.
Kind 32014 is never a Web-of-Trust hop. Ratings are ingested for authors
already on the kind 32009 frontier and queried with QUERY_RATING /
QUERY_RATING_BATCH. The two questions 32009 and 32014 answer are
in wot-questions.md.
Optional l tags on kind 32009 and kind 32014 augment the trust or rating
with further human clarification. They are not hops and are not part of d.
Kind 32009 trust statements#
NIP-32009 defines one addressable slot per author and d tag.
The required tags are:
- exactly one subject tag:
p,e, ori; d, alwayssha256(material)wherematerialissubject:scope:context;v:1for trust,0for Neutral,-1for distrust, or empty to Delete;- optional
k(identifier class) ands(domain/namespace); - optional
cfor a canonical hierarchical context (omit for global); - optional
llabels (augment the statement with further clarification; optional description ontag[2]; not ind; not a hop); - optional structured hints after the primary
p/e/ivalue (class:property:value), or a barenpub1…for the subject's linked Nostr pubkey; - optional
xandyactivation and expiration times.
The current X UI publishes stable i subjects:
user:id:<numeric-account-id>
post:id:<numeric-post-id>
Profile publishing is disabled until a numeric account ID is resolved; a
mutable handle is never a durable trust subject. New X person-trust statements
use s=x.com and c=identity. Post trust and ratings omit c. Older
empty-context user statements remain valid, and X prefers an x.com statement
over an empty-scope statement for the same author, subject, and context.
The second element of a p, e, or i tag is always the primary subject.
Later elements are advisory hints (class:property:value or bare npub1…).
Hints are ignored for graph edges and do not enter d.
The question control is deliberately local-only. It updates the current card and publishes no Nostr event.
Example account statement:
{
"kind": 32009,
"tags": [
["d", "<sha256(user:id:11348282:x.com:)>"],
["i", "user:id:11348282", "user:name:nasa", "npub1…"],
["k", "user:id"],
["s", "x.com"],
["v", "1"]
],
"content": ""
}
Example post statement:
{
"kind": 32009,
"tags": [
["d", "<sha256(post:id:2080659774136291424:x.com:)>"],
["i", "post:id:2080659774136291424"],
["k", "post:id"],
["s", "x.com"],
["v", "-1"]
],
"content": ""
}
Content is an optional short human explanation (ternary v is the machine
edge). Attention product policy: optional, never required; ~144-character
plain-text compose cap; show in path/detail views only; prefer reasons on
account trust over posts — see
design.md § Trust statement content.
Attention does not put X post bodies or X authentication data in events.
Validation and replacement#
Before storage or graph use, the backend verifies the Nostr shape, event hash,
signature, kind, one-subject rule, primary subject, subject-hint syntax
(structured or bare npub1…), value, canonical context, deterministic d
tag, activation/expiration interval, and content limits. Hints are excluded
from d, so changing them does not create a new replacement slot.
The newest valid event for (author pubkey, d) wins by greatest created_at;
the lexically lower event ID wins a timestamp tie. The winning empty-v event
Deletes the slot and does not revive an older statement. Neutral (v = "0")
is an active statement kept in the graph and shown in evidence lists, but is
not a traversal hop. Context lookup tries the exact context, its nearest
parents, then the empty general context, skipping deleted or inactive slots
along the way. Neutral occupies the slot and does not fall through.
Local WoT interpretation#
Positive active kind 32009 statements with a p subject are traversable
trust edges. Neutral and negative p statements are evidence but not
traversal edges.
e and i subjects, including X account and post subjects, are terminal
evidence.
Relay synchronization and query traversal are bounded by depth, fan-out,
authors, and event count. Data Synchronization settings choose interval
frontier REQ/EOSE (with a selectable wake interval), heap-frontier live
subscriptions, or Subscribe all (author-unfiltered live 32009 / 32014 /
10011 only — not an all-kinds firehose). Continuous modes keep the service
worker warm so live sockets and the Graph heap are not idled off between
events; interval mode may sleep until the next alarm. Query results retain
direct and reachable
statements, paths, source event IDs, graph version, and truncation state. The resolution is
trusted, distrusted, mixed, or none; it is local to the selected root
and context and is not an objective or numerical Web-of-Trust score.
Current winning signed events and reducer indexes are durable in IndexedDB; superseded addressable replacements should not be retained locally (see architecture.md § Minimal data and memory). Per-relay, per-scope cursors use an overlap window and advance after EOSE. Publishing is write-through to IndexedDB and a durable per-relay outbox before delivery is attempted.
Kind 32014 subject rating#
NIP-32014 defines an addressable score (0–100; empty
score = Delete) for “is this artifact worth my time?” It reuses kind 32009 d
material and subjects, is never a graph hop, and is resolved with exact c
only. See wot-questions.md. Attention stores winners in
the existing events table (addressKey = 32014:pubkey:d) and indexes
active claims beside the trust graph. Query aggregation uses the nearest
trusted degree only, matching kind 32009.
Kind 10011 X identity linking#
NIP-39 links the event author's Nostr key to an X account with two
matching i tags:
{
"kind": 10011,
"tags": [
["i", "twitter:nasa", "2080659774136291424", "post:id:2080659774136291424"],
["i", "twitter_id:11348282", "2080659774136291424", "post:id:2080659774136291424"]
],
"content": ""
}
Both tags retain the standard raw proof-post ID in element 3. The optional
fourth element repeats that reference in the structured hint form for clients
that understand scope-aware hints; legacy three-element tags remain valid. The
handle is informational; twitter_id is the stable account identifier. When
Attention updates this replaceable event, it removes prior X-provider tags
and preserves unrelated provider tags and content.
The backend generates the NIP-39 proof text and verifies the event signature
and matching twitter / twitter_id tags. A kind 10011 claim is recorded
from those tags. Attention does not fetch the public X profile to map the
handle to a numeric ID. Verified claims and provenance are persisted in
IndexedDB.
Linking an X account uses the bio workflow. Attention does not open X compose
to publish a proof post. Kind 10011 is published from the signed-in account's
handle and numeric ID.