forked from Hermes/nostr-cli
Nostr CLI for Cobot agents - keygen, DMs, identity management
- Python 99.6%
- Shell 0.4%
## What Replaces all custom cryptography and NIP-04 encryption with `nostr-sdk` (rust-nostr Python bindings) and NIP-44. ## Why - **NIP-04 is deprecated** — known vulnerabilities (no padding, IV reuse risks, metadata leaks) - **NIP-44** is the replacement (XChaCha20-Poly1305, HMAC-SHA256 key derivation, proper padding) - **4 dependencies → 1** — `websockets` + `cryptography` + `secp256k1` + `bech32` all replaced by `nostr-sdk` - `nostr-sdk` handles key management, event signing, relay connections, and encryption — no reason to reimplement any of it ## Changes ### Encryption - **Outgoing DMs:** NIP-44 V2 (was NIP-04) - **Incoming DMs:** NIP-44 first, NIP-04 fallback (backwards compatible) ### Dependencies - **Before:** `websockets`, `cryptography`, `secp256k1`, `bech32` - **After:** `nostr-sdk` (single dependency, Rust-backed) ### Key management - `generate_keypair()` → `Keys.generate()` - `load_identity()` → `Keys.parse()` (handles nsec, hex automatically) - No more manual bech32 ↔ hex conversion ### Relay communication - Custom websocket code → `nostr-sdk.Client` (connection pooling, auto-reconnect) - Event signing via `EventBuilder.sign_with_keys()` ### Unchanged - Injection shield (regex + local DeBERTa) - Wake mechanism - CLI interface and all commands ## Tests 28/28 passing — updated for nostr-sdk API, added NIP-44 roundtrip, NIP-04 backwards compat, and wrong-key-fails tests. Co-authored-by: Nazim <nazim@al-munazzim.github.io> Co-authored-by: Nazim <nazim@openclaw.ai> Reviewed-on: Hermes/nostr-cli#1 Co-authored-by: nazim <nazim@olymp.local> Co-committed-by: nazim <nazim@olymp.local> |
||
|---|---|---|
| .github/workflows | ||
| bin | ||
| .gitignore | ||
| nostr_cli.py | ||
| README.md | ||
| requirements.txt | ||
| test_e2e.py | ||
| test_nostr_cli.py | ||
Nostr CLI
Command-line tool for Nostr identity management and encrypted DMs (NIP-04).
Features:
- 🔑 Key generation (nsec/npub)
- 📨 Send & receive encrypted DMs
- 🛡️ Prompt injection shield (blocks malicious messages)
- ⚡ Wake mechanism (alert agents on new DMs)
Installation
# Create venv and install deps
python3 -m venv venv
./venv/bin/pip install -r requirements.txt
# Make CLI executable
chmod +x bin/nostr
# Add to PATH (optional)
export PATH="$PATH:$(pwd)/bin"
Commands
Generate Keypair
nostr keygen
Show Identity
export NOSTR_NSEC="nsec1..."
nostr whoami
Listen for DMs
nostr listen
With wake notifications:
nostr listen --wake-url http://localhost:18793/hooks/wake --wake-token filedrop-wake-olymp
Disable injection shield (not recommended):
nostr listen --no-shield
Send DM
nostr send npub1abc... "Hello!"
Test Wake
nostr wake --url http://localhost:18793/hooks/wake "Test message"
Environment Variables
| Variable | Description |
|---|---|
NOSTR_NSEC |
Private key (nsec1... or hex) |
NOSTR_WAKE_URL |
Wake endpoint URL |
NOSTR_WAKE_TOKEN |
Wake auth token |
NOSTR_AGENT_NAME |
Agent name (for registry lookup) |
NOSTR_REGISTRY |
Path to agents.json |
Security Features
Injection Shield (Two Layers)
Incoming DMs are scanned for prompt injection:
Layer 1: Regex (fast, ~80%)
- Instruction override attempts
- System prompt injection
- Roleplay jailbreaks
- Credential extraction
- Tool abuse attempts
Layer 2: Local DeBERTa Model (~99%, multilingual)
- Uses
protectai/deberta-v3-base-prompt-injection-v2 - Runs on olymp at
http://localhost:8080 - Catches obfuscated attacks, language switching, etc.
Disable local model with --no-local-shield (regex only).
Disable entirely with --no-shield.
Wake Mechanism
When a DM arrives, the CLI can notify an agent via webhook:
POST /hooks/wake
Authorization: Bearer <token>
{"text": "Nostr DM from npub1...: message preview", "mode": "now"}
Compatible with OpenClaw hooks and filedrop wake system.
Integration with agents.json
The CLI can read wake config from /olymp/agents.json:
{
"agents": {
"Hermes": {
"wake": {
"method": "hooks",
"url": "http://localhost:18793/hooks/wake",
"token": "filedrop-wake-olymp"
}
}
}
}
Set NOSTR_AGENT_NAME=Hermes to use this config.
Credits
- Original listener script by noopsec
- Refactored with shield + wake by Hermes 🪽