mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-30 07:37:38 +00:00
The 33 descriptions (~16k chars, ~19k with paths) overran Codex's skill-list budget (2% of the context window, or 8,000 chars when unknown), and a review found most bodies stale: paths from before the commons/commonsUI moves, the deleted legacy desktop app, a callback signer API that no longer exists, and example APIs that were never in the tree. Kept, rewritten and checked against the code (every path, class and command): account-state (+feeds), amy-expert, android-expert, auth-signers, compose-expert (+API style, Navigation 3 back stacks), desktop-expert (+run/package), event-store-semantics (+NIP-50 search), find-missing- translations, kotlin-coroutines (+structured concurrency, flow modeling), kotlin-multiplatform (+Gradle, composable extraction), ngit-pr, nip85-trusted-assertions, nostr-expert (+NIP lookup, generated NIP catalog), relay-client. Dropped: textbook Compose/Kotlin technique skills, kotlin-expert, kotlin-types-value-class, gradle-expert, quartz-integration (external-facing; see the Quartz docs commit), find-non-lambda-logs (audit finished; the rule is now in AGENTS.md Kotlin Style), and the /nip, /desktop-run, /extract commands. The skill list is now ~4k chars. Also drops .claude/core-skills-plan.md (stale history) and repoints SearchableEvent's KDoc to event-store-semantics. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.0 KiB
3.0 KiB
Event hierarchy
All in quartz/src/commonMain/kotlin/com/vitorpamplona/quartz/nip01Core/core/ unless noted.
IEvent (marker interface)
└── Event(id, pubKey, createdAt, kind, tags, content, sig) Event.kt, @Immutable, open
├── BaseReplaceableEvent kinds 0, 3, 10000–19999; dTag() = FIXED_D_TAG ("")
├── BaseAddressableEvent kinds 30000–39999; dTag() from tags, address() = Address(kind, pubKey, dTag)
└── every other typed event class (subclasses Event directly)
Both bases implement AddressableEvent (dTag(), address()), so a replaceable event
also has an Address — with an empty d-tag. BaseReplaceableEvent does not extend
BaseAddressableEvent.
Kind ranges (Kind.kt, verbatim)
fun Kind.isRegular() = this > 0 && this < 10_000 && this != ContactListEvent.KIND
fun Kind.isEphemeral() = this >= 20_000 && this < 30_000
fun Kind.isReplaceable() = this == MetadataEvent.KIND || this == ContactListEvent.KIND || (this >= 10_000 && this < 20_000)
fun Kind.isAddressable() = this >= 30_000 && this < 40_000
Note isRegular() excludes kind 0 and kind 3 and starts at 1, not 1000.
Shape of a typed event
Copy an existing class in the same NIP. TextNoteEvent (nip10Notes/TextNoteEvent.kt):
class TextNoteEvent(id: HexKey, pubKey: HexKey, createdAt: Long, tags: Array<Array<String>>, content: String, sig: HexKey) :
BaseThreadedEvent(id, pubKey, createdAt, KIND, tags, content, sig),
EventHintProvider, AddressHintProvider, PubKeyHintProvider, IForkableEvent, SearchableEvent {
companion object {
const val KIND = 1
fun build(note: String, replyingTo: EventHintBundle<TextNoteEvent>? = null, …,
initializer: TagArrayBuilder<TextNoteEvent>.() -> Unit = {}) =
eventTemplate(KIND, note, createdAt) { … initializer() }
}
}
House rules visible there:
- The constructor takes no
kind; it passes itsKINDconstant up. - Construction goes through a
companionbuild(...)that returns anEventTemplate<T>(unsigned); aNostrSignersigns it (signer.sign(template), seeauth-signers). - References to other events come in as
EventHintBundle<T>(nip01Core/hints/), which carries the relay hint along with the event.
Optional interfaces
| Interface | File | Purpose |
|---|---|---|
EventHintProvider / AddressHintProvider / PubKeyHintProvider |
nip01Core/hints/HintProviders.kt |
eventHints()/linkedEventIds() etc. — feed the relay-hint indexes and LocalCache gatherers |
SearchableEvent |
nip50Search/SearchableEvent.kt |
NIP-50 full-text indexing — see the event-store-semantics skill |
PrivateTagArrayEvent / PrivateReplaceableTagArrayEvent |
nip51Lists/ |
lists with NIP-44-encrypted private tags in content |
Validation (nip01Core/crypto/EventExt.kt)
generateId(), verifyId(), verifySignature(), verify(): Boolean, and
checkSignature() (throws). JSON: Event.fromJson(json) / Event.fromJsonOrNull(json) /
event.toJson() via OptimizedJsonMapper.