account-state
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
NIP-85 trusted assertions in Quartz: kind 10040 provider lists, 30382-30385 assertion cards, RankTag/HopsTag/ServiceType, GrapeRank publisher, contact-card nicknames. Use when building, parsing or ranking on these events.
Claude Code
$ npx -y skills add vitorpamplona/amethyst --skill nip85-trusted-assertions --agent claude-code
Codex
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a codex -y
Cursor
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a cursor -y
Gemini CLI
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a gemini-cli -y
GitHub Copilot
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a github-copilot -y
OpenCode
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a opencode -y
Windsurf
$ npx skills add vitorpamplona/amethyst --skill nip85-trusted-assertions -a windsurf -y
name: nip85-trusted-assertions description: NIP-85 trusted assertions in Quartz: kind 10040 provider lists, 30382-30385 assertion cards, RankTag/HopsTag/ServiceType, GrapeRank publisher, contact-card nicknames. Use when building, parsing or ranking on these events.
Package: `quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip85TrustedAssertions/`. NIP-85 is still an evolving spec; **this package is the operative definition** of what Amethyst-family software writes and reads. This skill states the model (who signs what about whom), the exact kind/d-tag/tag vocabulary, and what consumers may — and may not — assume.
An **assertion is signed by the asserting party** (a trust provider service, or the user themself) **about a subject named in the d-tag**. All assertion kinds are addressable, so "latest card by provider P about subject S" is just the addressable coordinate `(kind, P, S)` and supersession is standard NIP-01 latest-wins. Discovery is the observer's **kind 10040 list**: each entry says *"for metric M on kind K, I trust provider P — fetch their assertions at relay R"*. Quartz enforces none of this cryptographically beyond normal event signatures; the 10040→assertion link is **consumer-side convention** (see "Authorization" below).
| Kind | Class | Kind class | d-tag = the subject | Content | |---|---|---|---|---| | 10040 | `list/TrustProviderListEvent` | replaceable | *(none — always `""`)* | NIP-44 private provider entries (optional) | | 30382 | `users/UserAssertionEvent` | addressable | **target user's pubkey** (hex) | NIP-44 private tags (petname/summary/emoji) | | 30383 | `events/EventAssertionEvent` | addressable | **target event id** (hex) | `""` | | 30384 | `addressables/AddressableAssertionEvent` | addressable | **target coordinate** `kind:pubkey:dtag` | `""` | | 30385 | `externalIds/ExternalIdAssertionEvent` | addressable | **external identifier** (e.g. `isbn:978-0-13-468599-1`) | `""` |
Addresses: `UserAssertionEvent.createAddress(owner, target)` → `Address(30382, owner, target)` (owner = signer, target = subject). `TrustProviderListEvent.createAddress(pubKey)` uses `FIXED_D_TAG = ""`. `AssertionEventTest.eventKindsAreCorrect` pins all five numbers.
`UserAssertionEvent` is also a `SearchableEvent` — it indexes only the **public** petname/summary tags plus topics; the encrypted card content is intentionally never indexed.
There is **no fixed tag name**: `tag[0]` *is* the service string.
["30382:rank", "<provider pubkey, 64 hex>", "wss://nip85.brainstorm.world"]
`:` splits, colons in the remainder stay in `type`. `ServiceType.isOfKind` is the allocation-free prefix check.
(length-only check), and a **normalizable relay URL** (`RelayUrlNormalizer.normalizeOrNull`) — entries failing any check are silently dropped, which is what keeps foreign tags like `["client","nostria"]` out (regression-tested in `ServiceTypeParserTest`).
`isPrivate`. `remove` always needs decryption and strips from both sides by parsed-value equality.
`30382:rank`, `30382:followers`, `30382:first_created_at`, per-metric `30383:*`/`30384:*`/ `30385:*`, etc. It is an **open vocabulary**: real 10040s in the wild (see the fiatjaf → brainstorm fixture in `commonTest/.../experimental/nip85TrustedAssertions/ServiceParser.kt`) carry types Quartz doesn't enumerate (`30382:personalizedGrapeRank_influence`, `30382:hops`, `30382:verifiedFollowersCount`, …). Parse any `kind:type`; special-case only what you rank on.
observer's 10040 for a matching service type.** Quartz does not enforce this; the consuming code does. The in-repo pattern is `commons/.../model/nip85TrustedAssertions/UserCardsCache.kt`: `rankFlow(trustProviderList)` picks the received card whose **author pubkey equals the provider entry's pubkey** and reads `rank()` from it. Assertions from unlisted signers are simply ignored for trust purposes (they may still be stored; dropping them — as an external store's orphan sweep does — is a legitimate storage policy, not a protocol rule).
provider's user-rank cards, nothing else. Amethyst models this as one provider slot per metric (`liveUserRankProvider`, `liveUserFollowerCount`: the interface is `commons/.../model/nip85TrustedAssertions/TrustProviderListState.kt`, the account's implementation `commons/.../model/trustedAssertions/TrustProviderListState.kt`).
ranks, there is no spec'd merge; Amethyst avoids the question by selecting one provider per metric slot. Consumers choose their own policy — document it.
`commons/.../relayClient/user/watchers/UserCardsSubAssembler.kt` subscribes for cards at the provider's declared relay via `filterUserAssertionsToTargetKeysFromTrustedAccountsInTheRelay` (`relayClient/assemblers/ContactCardFilters.kt`: user-assertion kinds, `authors=[providers]`, `#d=[targets]`).
The same kind serves two roles, distinguished **by author**:
1. **Provider WoT cards** — signed by a trust provider; public metric tags (`rank`, `followers`, `hops`, …); this is what 10040 dis
Account, LocalCache, User/Note and feeds in commons/model + commons/feeds: per-user XState objects (.flow),…
amy CLI in cli/: adding an `amy <verb>` command, Main.kt dispatch, Output.emit/--json contract, exit codes 0/1/2/124, ~/.amy…
Android shim in `amethyst/`: MainActivity, AndroidManifest/intent filters, :napplet process, play/fdroid flavors, R8 +…
NostrSigner in Amethyst: NostrSignerInternal (local key), NostrSignerRemote (NIP-46 bunker), NostrSignerExternal (NIP-55 Android…
Shared Compose UI in `commonsUI/`: screens, components, the nav shell (`ScreenLayoutSpec`, `AppShellLayout`, Navigation 3 back…
Desktop JVM shim in desktopApp/: AmethystDesktop window, DesktopMenuBar, platform ports, OS keyring; :desktopApp:run, packaging.…
Decompile Android APK, XAPK, JAR, and AAR files using jadx or Fernflower/Vineflower. Reverse engineer Android apps, extract HTTP…