5.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Is
Wrystr is a cross-platform Nostr desktop client built with Tauri 2.0 (Rust) + React + TypeScript. It connects to Nostr relays via NDK (Nostr Dev Kit) and aims for Telegram Desktop-quality UX. Long-form content (NIP-23) is a first-class, distinguishing feature — not an afterthought.
Commands
npm run tauri dev # Run full app with hot reload (recommended for development)
npm run dev # Vite-only dev server (no Tauri window)
npm run build # TypeScript compile + Vite build
npm run tauri build # Production binary
Prerequisites: Node.js 20+, Rust stable, @tauri-apps/cli
Releasing a New Version
Order matters — do not tag before bumping versions.
- Bump version to
X.Y.Zin all four files (they must stay in sync):src-tauri/tauri.conf.json→"version": "X.Y.Z"package.json→"version": "X.Y.Z"src-tauri/Cargo.toml→version = "X.Y.Z"PKGBUILD→pkgver=X.Y.Z
- Update the release notes in
.github/workflows/release.yml - Commit:
git commit -m "Bump to vX.Y.Z — <summary>" - Tag:
git tag vX.Y.Z - Push:
git push origin main vX.Y.Z
CI triggers on the tag and builds all three platforms (Ubuntu, Windows, macOS ARM). All jobs must complete for latest.json to be assembled.
Hard-won CI rules:
includeUpdaterJson: truemust be set in tauri-action — without itlatest.jsonis never uploaded and the auto-updater silently does nothingbundle.createUpdaterArtifacts: truemust be set intauri.conf.json— without it.sigfiles are never generated even if the signing key is set (Tauri 2 requirement)- Valid
bundle.targets:"deb","rpm","nsis","msi","dmg"— do NOT add"updater"(that's a plugin, not a bundle format) - macOS runner is
macos-latest(ARM only) —macos-12/macos-13are gone - Verify after CI:
https://api.github.com/repos/hoornet/wrystr/releases/latest(check for.sigassets +latest.json)
Architecture
Frontend (src/): React 19 + TypeScript + Vite + Tailwind CSS 4
src/App.tsx— root component; showsOnboardingFlowfor new users, then view routing via UI storesrc/stores/— Zustand stores per domain:feed.ts,user.ts,ui.ts,lightning.tssrc/lib/nostr/— NDK wrapper (client.ts+index.ts); all Nostr calls go through heresrc/lib/lightning/— NWC client (nwc.ts); Lightning payment logicsrc/hooks/—useProfile.ts,useReactionCount.tssrc/components/feed/— Feed, NoteCard, NoteContent, ComposeBoxsrc/components/profile/— ProfileView (own + others, edit form)src/components/thread/— ThreadViewsrc/components/search/— SearchView (NIP-50, hashtag, people)src/components/article/— ArticleEditor (NIP-23)src/components/bookmark/— BookmarkViewsrc/components/zap/— ZapModalsrc/components/onboarding/— OnboardingFlow (welcome, create key, backup, login)src/components/shared/— RelaysView, SettingsView (relay mgmt + NWC + identity)src/components/sidebar/— Sidebar navigation
Backend (src-tauri/): Rust + Tauri 2.0
src-tauri/src/lib.rs— Tauri app init and command registration- Rust commands must return
Result<T, String> - Future: OS keychain for key storage, SQLite, lightning node integration
Key Conventions (from AGENTS.md)
- Functional React components only — no class components
- Never use
any— define types insrc/types/ - Tailwind classes only — no inline styles, except unavoidable WebkitUserSelect
- Private keys must never be exposed to JS; use OS keychain via Rust (not yet implemented — nsec currently lives in NDK signer memory only)
- New Zustand stores per domain when adding features
- NDK interactions only through
src/lib/nostr/wrapper - Lightning/NWC only through
src/lib/lightning/wrapper
NIP Priority Reference
- P1 (core): NIP-01, 02, 03, 10, 11, 19, 21, 25, 27, 50
- P2 (monetization): NIP-47 (NWC/Lightning), NIP-57 (zaps), NIP-65 (relay lists)
- P3 (advanced): NIP-04/44 (DMs), NIP-23 (articles), NIP-96 (file storage)
Current State
Implemented:
-
Onboarding: key generation, nsec backup flow, login with nsec/npub
-
Global + following feed, compose, reply, thread view
-
Reactions (NIP-25) with live network counts
-
Follow/unfollow (NIP-02), contact list publishing
-
Profile view + edit (kind 0)
-
Long-form article editor (NIP-23) with draft auto-save
-
Zaps: NWC wallet connect (NIP-47) + NIP-57 via NDKZapper
-
Search: NIP-50 full-text, hashtag (#t filter), people
-
Settings: relay add/remove (persisted to localStorage), NWC URI, npub copy
-
Relay connection status view
-
Image lightbox (click to expand, arrow key navigation)
-
Bookmark list (NIP-51 kind 10003) with sidebar nav
-
Follow suggestions / discovery (follows-of-follows algorithm)
-
Language/script feed filter (Unicode script detection + NIP-32 tags)
-
Skeleton loading states, view fade transitions
-
src/components/shared/ImageLightbox.tsx— full-screen image viewer -
src/stores/bookmark.ts— bookmark store (mirrors mute store pattern) -
src/components/bookmark/BookmarkView.tsx— saved notes view -
src/lib/language.ts— Unicode script detection for feed filtering
Not yet implemented:
- OS keychain integration (Rust) — nsec lives in NDK memory only
- SQLite local note cache
- Direct messages (NIP-44/17)
- Reading long-form articles (NIP-23 reader view)
- Zap counts on notes
- NIP-65 outbox model
- NIP-17 DMs (gift wrap)