This document outlines the coding standards and best practices for the Mostro CLI project. These guidelines ensure code quality, maintainability, and consistency across the codebase.
Priority: Code should be written for humans first, machines second.
- Clear naming: Use descriptive names for functions, variables, and modules (e.g.,
parse_dm_eventsvspde). - Function reuse: Extract common logic into reusable functions. Place shared utilities in appropriate modules (
src/util/,src/parser/, etc.). - Module organization: Group related functionality together (CLI commands in
src/cli/, Protocol parsing insrc/parser/, Utilities insrc/util/).
Don't Repeat Yourself: If the same logic appears in multiple places, extract it.
- Extract common patterns: Create helper functions for repeated operations like DM sending.
- Centralize constants: Import from
mostro-core::preludeinstead of hardcoding values.
Keep It Simple: Prefer straightforward solutions over clever ones.
- Avoid premature optimization: Write clear code first, optimize only when needed.
- Prefer explicit over implicit: Use
OptionandResulttypes explicitly rather than hiding errors withunwrap().
Maximum 300 lines per function: If a function exceeds this limit, split it into smaller, single-responsibility functions.
- Use
Result<T, E>: Functions that can fail should returnResult. - Use
anyhow::Result: For application-level errors, useanyhow::Result<T>. - Propagate errors: Use the
?operator to propagate errors up the call stack. - Add context: Use
.context("...")fromanyhowto add meaningful error messages.
- Use strong types: Prefer newtypes or enums (
Action,Status) over primitive types. - Leverage enums: Use enums for state machines and role management.
- Prefer async/await: Use
async fnfor I/O and network operations. - Handle timeouts: Use
tokio::time::timeoutfor network operations.
- Document public APIs: Use
///doc comments for public functions and types. - Explain "why": Document the reasoning behind complex logic, not just "what".
- Markdown standards: All markdown documentation must pass linter checks with no errors.
- Run markdown linters to catch formatting issues (MD040, MD060, MD022, MD032, etc.).
- Fix all linter errors before committing documentation changes.
- Use proper table formatting with spaces around pipes.
- Specify language for all fenced code blocks.
- Add blank lines around headings and lists.
- Use constants: Always use constants from
mostro-core::prelude(e.g.,NOSTR_ORDER_EVENT_KIND). - Never hardcode: Avoid hardcoding event kind numbers like 38383.
- Parse DMs consistently: Use
parse_dm_eventsfor all DM parsing. - Support multiple message types: Handle both GiftWrap (NIP-59) and PrivateDirectMessage (NIP-17).
- Identity vs Trade Keys:
- Identity keys (index 0): User's main identity, used for signing.
- Trade keys (index 1+): Ephemeral keys for each trade, ensuring privacy.
src/
├── main.rs # Entry point
├── cli.rs # CLI definitions and Context
├── db.rs # Database models (User, Order)
├── cli/ # CLI command implementations
├── parser/ # Event parsing and display
└── util/ # Core utilities (events, messaging, net)
Use mod.rs files to re-export commonly used items from submodules to keep imports clean.
- User Model: Use chainable setters and the
.save()pattern. - Order Management: Use
Order::new()to handle both insertion and updates.
All CLI commands follow a standard flow:
- Validate inputs.
- Get required keys (Identity/Trade).
- Build the Mostro message.
- Send to Mostro (NIP-59).
- Wait for response (Subscription).
- Parse and display results.
- Code is readable and well-named.
- No code duplication (DRY).
- Functions are under 300 lines.
- Errors are handled properly (
Result,?). - Event kinds use constants from
mostro-core. - Both GiftWrap and PrivateDirectMessage are supported.
- Public APIs are documented.
- All markdown documentation passes linter checks with no errors.
- Code passes
cargo fmtandcargo clippy. - Tests pass (
cargo test).