Nostream ships a unified command-line interface:
nostream --help
pnpm run cli -- --helpWhen run with no arguments in an interactive terminal, nostream launches an interactive TUI.
In non-interactive environments, it prints help and exits successfully.
0: success1: runtime/validation error2: usage error (invalid command/options)
nostream start [--tor] [--i2p] [--nginx] [--debug] [--port 8008]
nostream stop [--all|--tor|--i2p|--nginx|--local]
nostream info [--tor-hostname] [--i2p-hostname] [--json]
nostream update
nostream clean
nostream setup [--yes] [--start]
nostream seed [--count 100]
nostream invite create [--uses N] [--expires-in <seconds>] [--json]
nostream import [file.jsonl|file.json] [--file file.jsonl|file.json] [--batch-size 1000]
nostream export [output] [--output output] [--format jsonl|json]Join (kind 28934) is already implemented. Operators mint a claim string and share it out of band; the client then publishes a join request with a claim tag.
# Local PostgreSQL (DB_URI or DB_HOST in the environment / .env)
nostream invite create
nostream invite create --uses 3 --expires-in 86400 --json
# Docker: Postgres is not published to the host
docker compose exec nostream node src/cli/index.js invite create--uses defaults to nip43.defaultMaxUses (1). --expires-in defaults to nip43.inviteCodeExpirySeconds (600 = 10 minutes). --expires-in must be a positive integer; never-expiring codes are a yaml policy (nip43.inviteCodeExpirySeconds: 0), not a CLI flag. The printed code is the first line of human output so scripts can capture it. If info.self is a hex pubkey or npub1…, it is stored as created_by.
The relay also answers REQs for kind 28935 by minting a code on the fly and returning it as a relay-signed ephemeral event, so users can obtain a claim string without an operator handing one out. It is off by default and requires nip43.enabled, nip43.allowInviteRequests and a NIP-42 authenticated client — see CONFIGURATION.md. Membership list events (kind 13534) are not published yet.
Invites minted over REQ record the requesting pubkey as created_by; nostream invite create records info.self.
NIP-43 clients verify relay-signed events against the self field of the NIP-11 document, so self must match the key the relay actually signs with. That key is derived from SECRET and is otherwise invisible, so nostream info prints it:
nostream info | grep 'Signing pubkey'
nostream info --json # same value under relay.signingPubkeyLeave info.self unset in settings to have this value advertised automatically. Set it only if you want to pin it explicitly, and set it to exactly this value — a mismatch disables kind 28935 invite requests.
The old shell wrapper scripts are no longer shipped in scripts/.
Use the unified nostream CLI directly instead:
scripts/start -> nostream start
scripts/start_with_tor -> nostream start --tor
scripts/start_with_i2p -> nostream start --i2p
scripts/start_with_nginx -> nostream start --nginx
scripts/stop -> nostream stop
scripts/print_tor_hostname -> nostream info --tor-hostname
scripts/print_i2p_hostname -> nostream info --i2p-hostname
scripts/update -> nostream update
scripts/clean -> nostream cleannostream config list
nostream config list --json
nostream config get <path>
nostream config get <path> --json
nostream config set <path> <value> [--type inferred|json] [--validate|--no-validate] [--restart]
nostream config validate
nostream config env list [--show-secrets]
nostream config env get <key> [--show-secrets]
nostream config env set <key> <value>
nostream config env validatePath syntax supports dot keys and array indexes:
nostream config get limits.event.content[0].maxLength
nostream config set limits.event.content[0].maxLength 2048
nostream config set nip05.domainWhitelist '["example.com","relay.io"]' --type jsonnostream dev db:clean [--all|--older-than=30|--kinds=1,7,4] [--dry-run] [--force]
nostream dev db:reset [--yes]
nostream dev seed:relay
nostream dev docker:clean [--yes]
nostream dev test:unit
nostream dev test:cli
nostream dev test:integrationRun:
nostreamMain menu includes:
- Start relay
- Stop relay
- Configure settings
- Manage data (export/import)
- Development tools
- View relay info
- Exit
TUI behavior highlights:
- Each submenu includes an explicit
Backoption, so you can return without using signal keys. - Start menu prompts for Tor/I2P/Debug, optional custom port, and final confirmation.
- Configure menu offers guided editing for common categories such as payments, network, and limits.
- Advanced dot-path get/set remains available for full settings access.
- Manage menu asks for import/export format and file paths.
- Dev menu displays explicit destructive warnings before DB reset/clean and Docker clean.
# Start relay with Tor + I2P
nostream start --tor --i2p
# Print Tor hostname
nostream info --tor-hostname
# Machine-readable output for automation
nostream info --json
nostream config list --json
nostream config get payments.enabled --json
# Import and export events
nostream import --file ./events.jsonl --batch-size 500
nostream import --file ./events.json --batch-size 500
nostream export --output backup.jsonl --format jsonl
nostream export --output backup.json --format json
# Update YAML settings and restart relay
nostream config set payments.enabled true --restart
# Update env settings
nostream config env set RELAY_PORT 8008
nostream config env get SECRET --show-secrets
nostream config env validate
# Mint a NIP-43 invite code (kind 28934 join)
nostream invite create --json
docker compose exec nostream node src/cli/index.js invite create