Files
2026-04-08 15:37:42 -07:00

4.3 KiB

Coracle Nostr Monorepo

Project Overview

This is a literate programming monorepo for building nostr applications in Rust. The source of truth is book/, which contains markdown files. Code blocks annotated with {file=path} are extracted ("tangled") into Rust source files by coracle-tangle. The src/ directories of library crates are generated artifacts — never edit them directly.

The project serves three goals:

  1. A complete learning resource for the nostr protocol
  2. A production-ready nostr utility library for Rust, KMP, and web projects
  3. An experiment in literate programming as both library and LLM context

Crates

  • coracle-lib — Core nostr types and stateless utilities
  • coracle-net — Relay networking
  • coracle-signer — Signing abstractions (NIP-07, NIP-46, local key)
  • coracle-domain — Domain-specific nostr types (profiles, follows, reactions, zaps, etc.)
  • coracle-content — Text parsing and rendering
  • coracle-storage — Cross-platform storage adapters
  • coracle-tangle — The tangle/weave build tool (not a library)

Bindings

Platform bindings are provided via separate crates, keeping the core library free of platform-specific annotations:

  • coracle-wasm — Web bindings via wasm-bindgen, producing JS-friendly types
  • coracle-ffi — C-compatible FFI via UniFFI, consumed by KMP (Kotlin Multiplatform)

These are separate crates (not feature flags in a single crate) because they have different dependencies, build toolchains, and API surfaces.

Build Commands

just tangle   # Extract code from markdown into .rs files
just build    # tangle + cargo build (excludes coracle-tangle)
just check    # tangle + cargo check
just weave    # tangle + mdbook build
just clean    # Remove all generated src/ and book output
just all      # build + weave — use this to validate work

Always run just all to validate changes.

Literate Programming Conventions

  • Each chapter in book/ corresponds to a topic (events, keys, relays, etc.)
  • Code blocks with {file=crate/src/path.rs} annotations are tangled into source files
  • Multiple blocks targeting the same file are concatenated in document order
  • Code blocks without annotations are illustrative only
  • The narrative should flow naturally — explain why before showing what
  • Write prose that a developer new to nostr could follow from start to finish

Reference Materials

The ref/ directory contains resources used for research, split into two categories.

Philosophy

Directory Description
ref/building-nostr High-level ideas about what nostr is and how to work with it — philosophy, not code

This resource should inform the narrative voice, design philosophy, and conceptual framing of chapters, but is not a source of implementation patterns.

Implementations

Directory Language Description
ref/applesauce TypeScript Libraries for building nostr web clients (noStrudel)
ref/ndk TypeScript Nostr Development Kit with framework integrations
ref/nostr-gadgets TypeScript High-level nostr client utilities (JSR)
ref/nostr-tools TypeScript Low-level nostr tools, minimal dependencies
ref/rust-nostr Rust Full Rust implementation with multiple crates
ref/welshman TypeScript Nostr toolkit extracted from the Coracle client

Chapter Workflow

Chapters are developed in three phases using slash commands:

  1. /research-chapter <name> — Asks the user for a topic summary, then spawns sub-agents to analyze how each reference implementation handles the topic. Only reports on functionality relevant to the chapter. Output: book/research/<name>.md

  2. /plan-chapter <name> — Reads the research file and enters interactive Q&A with the user to develop a detailed chapter plan. Output: book/plan/<name>.md

  3. /write-chapter <name> — Reads the chapter plan and writes the actual chapter markdown with tangled code blocks. Validates with just all.

Code Style

  • Rust code should be idiomatic and well-documented
  • Prefer clarity over cleverness — this is a teaching resource
  • Keep dependencies minimal
  • All public items need doc comments that explain the why
  • Code must compile and pass just all before a chapter is considered complete