# ndr
CLI for encrypted Nostr messaging using the double ratchet protocol.
Designed for humans, AI agents, and automation. Compatible with [chat.iris.to](https://chat.iris.to).
## Installation
```bash
cargo install ndr
```
Or build from source:
```bash
cargo install --path .
```
## Quick Start
```bash
# Login with a private key (hex or nsec)
ndr login <private_key>
# Check identity
ndr whoami
# Create an invite
ndr invite create
# Publish a device invite (default device id = your identity pubkey hex)
ndr invite publish
# Join someone's invite
ndr chat join <invite_url>
# Send a message
ndr send <chat_id> "Hello!"
# Read messages
ndr read <chat_id>
# Listen for new messages in real-time
ndr listen
```
## JSON Mode
Use `--json` flag for machine-readable output (for scripts and AI agents):
```bash
ndr --json whoami
ndr --json chat list
ndr --json send abc123 "Hello from automation"
```
## Commands
### Identity
```bash
ndr login <key> # Login with private key (hex or nsec)
ndr logout # Logout and clear data
ndr whoami # Show current identity
```
### Invites
```bash
ndr invite create # Create new invite URL
ndr invite publish # Create + publish invite event on Nostr (default device id: your pubkey hex)
ndr invite list # List pending invites
ndr invite delete <id> # Delete an invite
ndr invite listen # Listen for invite acceptances
```
Notes:
- `ndr invite publish` defaults to device id = your identity pubkey (hex), matching Iris multi-device expectations.
- Re-run `ndr invite publish` to refresh the device invite.
- If you want a single "public" invite per identity across devices, use `--device-id public`.
### Link Devices
```bash
# On the device to be linked
ndr link create # Create a private link invite (stores it locally)
# On the owner device
ndr link accept <url> # Accept the link invite, publish response, and register device in AppKeys
# Back on the device to be linked
ndr listen # Wait for the response and finalize linking
```
### Chats
```bash
ndr chat list # List all chats
ndr chat join <url> # Join via invite URL, or Iris-style chat link: https://chat.iris.to/#npub1...
ndr chat show <id> # Show chat details
ndr chat delete <id> # Delete a chat
```
### Messages
```bash
ndr send <chat_id> <msg> # Send encrypted message
ndr send <npub> <msg> # Auto-accept their public invite if no chat exists
ndr send <chat_link> <msg> # Same, but with https://chat.iris.to/#npub1... style links
ndr react <chat_id> <msg_id> <emoji> # React to a message
ndr read <chat_id> # Read message history
ndr listen # Listen for incoming messages
ndr listen --chat <id> # Listen on specific chat
```
### Groups
```bash
ndr group create --name <name> --members <owner_pubkey_csv>
ndr group list
ndr group show <group_id>
ndr group update <group_id> [--name ...] [--description ...] [--picture ...]
ndr group add-member <group_id> <owner_pubkey>
ndr group remove-member <group_id> <owner_pubkey>
ndr group add-admin <group_id> <owner_pubkey>
ndr group remove-admin <group_id> <owner_pubkey>
ndr group accept <group_id>
ndr group send <group_id> <msg>
ndr group react <group_id> <msg_id> <emoji>
ndr group rotate-sender-key <group_id>
ndr group messages <group_id>
```
## Configuration
Default data directory: `~/.local/share/ndr/` (Linux) or platform equivalent.
Override with `--data-dir` flag or `NDR_DATA_DIR` environment variable.
Create `config.json` in data directory to configure relays:
```json
{
"relays": ["wss://relay.example.com"]
}
```
## Examples
### Create an invite and wait for response
```bash
# Alice creates invite
ndr invite create
# Output: invite URL
# Alice listens for responses
ndr invite listen
# Bob joins (on his machine)
ndr chat join "https://..."
# Alice sees session created, can now send messages
ndr send <chat_id> "Hello Bob!"
```
### Send to npub using a public invite
```bash
# Bob publishes a public invite
ndr invite publish
# Alice can send directly to Bob's npub
ndr send npub1... "Hello Bob!"
```
### AI Agent Integration
```bash
# Agent receives message event from relay
event='{"kind":1060,"content":"...",...}'
# Decrypt and process
ndr --json receive "$event"
# Output: {"status":"ok","data":{"chat_id":"...","content":"Hello!"}}
# Reply
ndr --json send <chat_id> "I received your message"
```
## Security Notes
- Outer events are signature-verified; sender attribution is resolved from authenticated session context plus owner/device mapping.
- `ownerPubkey` claims are checked against AppKeys in multi-device flows.
- Inner rumor `pubkey` is not treated as trusted sender identity.
- Inner message payloads are unsigned and deniable; do not treat them as non-repudiable signatures.