11 files updated to reflect current state (v0.0.22 → v0.0.46): ARCHITECTURE.md: - Ring tones, group calls, read receipts, markdown rendering sections - Bot API expanded (BotFather, numeric IDs, Telegram compat) - Admin commands, known issues, 155 tests TASK_PLAN.md: - All P1-P4 marked DONE with version numbers - Additional completed work section (bots, ETH, ring tones, group calls) - New FC-P7 (Voice & Transport): cpal, Sender Keys, WebTransport - FC-P6-T9/T10 added PROGRESS.md: - Full version history table v0.0.22 through v0.0.46 - Known issues section README.md: - Voice calls, ring tones, group calls, read receipts, markdown, 155 tests SECURITY.md: - Bot API security, voice call security, admin commands sections - Updated protection tables USAGE.md: - Group calls, read receipts, markdown formatting, admin commands CLIENT.md: - Call commands, read receipts, markdown rendering LLM_HELP.md + LLM_BOT_DEV.md: - Call/group call/admin commands, ring tones, per-bot numeric IDs TESTING_E2E.md: - Tests 16-18: ring tones, group calls, admin commands CLAUDE.md: - Ring tone notes, group signal endpoint, MLS roadmap Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
featherChat Help Reference
featherChat (codename: warzone) = E2E encrypted messenger. TUI client, web client (WASM), federated servers. Crypto: X3DH key exchange + Double Ratchet. Identity = Ed25519 keypair from 24-word seed.
Commands
| cmd | action | example |
|---|---|---|
| /help, /? | show help | /help |
| /info | show your fp | /info |
| /eth | show ETH addr | /eth |
| /seed | show 24-word recovery mnemonic | /seed |
| /peer , /p | set DM peer | /peer abc123 or /peer @alice |
| /reply, /r | reply to last DM sender | /r |
| /dm | switch to DM mode (clear peer) | /dm |
| /contacts, /c | list contacts + msg counts | /c |
| /history, /h [fp] | show conversation history (50 msgs) | /h abc123 |
| /alias | register alias for yourself | /alias alice |
| /aliases | list all registered aliases | /aliases |
| /unalias | remove your alias | /unalias |
| /friend | list friends + online status | /friend |
| /friend | add friend | /friend @bob |
| /unfriend | remove friend | /unfriend @bob |
| /devices | list active device sessions | /devices |
| /kick | kick a device session | /kick dev_abc |
| /g | switch to group (auto-join) | /g ops |
| /gcreate | create group | /gcreate ops |
| /gjoin | join group | /gjoin ops |
| /glist | list all groups | /glist |
| /gleave | leave current group | /gleave |
| /gkick | kick member (creator only) | /gkick abc123 |
| /gmembers | list group members + status | /gmembers |
| /call | start voice call with current peer | /call |
| /call | start voice call with specific peer | /call @alice |
| /accept | accept incoming call | /accept |
| /reject | reject incoming call | /reject |
| /hangup | end current call | /hangup |
| /gcall | start group voice call in current group | /gcall |
| /gjoin | join active group call | /gjoin |
| /gleave-call | leave group call (stay in group) | /gleave-call |
| /gmute | toggle mute in group call | /gmute |
| /admin-calls | list active calls on server (admin) | /admin-calls |
| /admin-help | show admin commands (admin) | /admin-help |
| /file | send file (max 10MB, 64KB chunks) | /file ./doc.pdf |
| /quit, /q | exit | /q |
Navigation: PageUp/PageDown scroll msgs, Up/Down scroll by 1 (empty input), Ctrl+C or Esc quit.
Addressing
| Format | Example | Notes |
|---|---|---|
| Fingerprint | abc123def456... | hex string, derived from Ed25519 pubkey |
| ETH address | 0x742d35Cc... | derived from same seed, checksum format |
| @alias | @alice | 1-32 alphanum chars, globally unique, 365d TTL |
All 3 formats work in /peer. Aliases resolve to fp via server. One alias per user. Register with /alias, recover with recovery key.
Bot alias reservation: names ending in Bot, bot, or _bot are reserved for the Bot API. Non-bot users cannot register these aliases.
Quick Start
warzone init-- generates seed, saves identity.seed, prints 24-word mnemonic. WRITE IT DOWN.warzone register --server https://srv.example.com-- uploads prekey bundle to srvwarzone tui --server https://srv.example.com-- opens TUI, connects WebSocket/peer @aliceor/peer <fingerprint>-- set recipient- Type msg, press Enter -- encrypted + sent
Recovery: warzone recover -- enter 24 words to restore identity on new device.
Groups
- /gcreate -- create, you become creator + first member
- /gjoin -- join existing (or auto-join via /g )
- type msg in group mode -- fan-out encrypted per-member (sender keys)
- /gleave -- leave current group
- /gmembers -- shows fp, alias, online status, creator flag
- /gkick -- creator only, removes member
Groups auto-create on join if they don't exist. Server fans out per-member encrypted msgs.
Files
/file -- sends to current peer/group. Max 10MB. Auto-chunked at 64KB. Includes filename, size, SHA-256 hash. Receiver auto-reassembles.
Friends
- /friend -- list all friends with online/offline status
- /friend -- add (fp, ETH, or @alias)
- /unfriend -- remove
- Friend list stored encrypted on srv (only you can decrypt with your seed)
- Shows alias resolution + presence status
Devices
- /devices -- list active WS connections (device_id, connected_at)
- /kick <device_id> -- revoke specific device
- Max 5 concurrent device sessions
- /devices/revoke-all API endpoint = panic button (kills all except current)
Security
- Seed = 24-word BIP39 mnemonic = master key. Derives Ed25519 identity + ETH wallet.
- NEVER share seed. Only way to recover account.
- X3DH key exchange establishes sessions. Double Ratchet provides forward secrecy.
- All DMs E2E encrypted. Group msgs encrypted per-member.
- Server sees: metadata (who talks to whom, timestamps), encrypted blobs, presence.
- Server cannot read msg content.
- Pre-keys: signed pre-key + 10 one-time pre-keys uploaded on register.
- Bot msgs: clients auto-detect bot aliases, send plaintext (no E2E). Server can read bot msgs.
- E2E bots possible (register with seed+bundle) but standard bots are plaintext.
Federation
- 2 servers connected via persistent WebSocket
- Config: JSON file with server_id, shared_secret, peer URL
- Messages auto-route across servers (srv checks remote presence)
- Aliases globally unique across federation
- @alias resolution checks local first, then federated peer
- Same client commands work regardless of which srv peer is on
- Auto-reconnects on connection failure
Web Client
- Browser access at server root URL (/)
- WASM-compiled client, same crypto as TUI
- PWA: installable, offline-capable (service worker caches shell)
- Same E2E encryption as native client
- Deep links: navigate to specific peers/groups via URL
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| "peer not registered" | recipient hasn't run register yet | they need to warzone register |
| "session reset" | crypto session re-established | normal after key rotation or recovery, msgs continue |
| "connection lost" | WS disconnected | auto-reconnects, no action needed |
| "alias already taken" | someone else has it | pick different name or wait for 365d expiry + 30d grace |
| "not a member" | sending to group you left | /gjoin first |
| "invalid token" | bot token expired or wrong | re-register bot |
| "file too large" | over 10MB | split file manually |
| no prekeys available | recipient's one-time prekeys exhausted | they need to re-register or come online |
Bot API (Telegram-compatible)
Creating a Bot
Server must run with --enable-bots. Then in chat:
/peer @botfather
/newbot MyWeatherBot
→ BotFather replies with token
BotFather commands: /newbot, /mybots, /deletebot , /token , /help
Bot names must end with bot/Bot/_bot. Only @botfather can create bots.
Plaintext Bot Messaging
Clients auto-detect bot aliases (names ending in Bot/bot/_bot) and send messages unencrypted (plaintext JSON). No E2E session is established for standard bot interactions.
E2E Bot Option
Bots can optionally participate in E2E encryption by registering with a seed and prekey bundle. Pass e2e: true + bundle + eth_address in the registration request. Users messaging an E2E bot establish a normal X3DH session.
Bot Bridge
tools/bot-bridge.py provides Telegram library compatibility. It translates between featherChat Bot API and standard TG bot libraries (python-telegram-bot, aiogram, Telegraf).
Endpoints
| Endpoint | Method | Body |
|---|---|---|
| /bot/:token/getMe | GET | -- |
| /bot/:token/getUpdates | POST | {"timeout":50} |
| /bot/:token/sendMessage | POST | {"chat_id":"<fp_or_numeric>","text":"Hello","parse_mode":"HTML"} |
| /bot/:token/setWebhook | POST | {"url":"https://..."} |
| /bot/:token/deleteWebhook | POST | -- |
| /bot/:token/getWebhookInfo | GET | -- |
- Token format: fp_prefix:random_hex
- getUpdates: long-poll (max 50s), returns then deletes queued msgs
- sendMessage: plaintext JSON, NOT E2E encrypted (unless E2E bot)
- Bot msgs delivered via same routing (WS push or DB queue)
- Webhooks: updates are delivered live to the registered URL (POST with JSON body)
- chat_id: accepts hex fingerprint or numeric ID (TG compatibility)
- parse_mode:
HTMLrenders basic HTML tags (, ,, ) in clients - from.id is per-bot unique numeric (bots can't correlate users cross-bot, no raw fingerprint exposed)
Update types in getUpdates:
- Encrypted msg: text=null, raw_encrypted=base64
- Bot msg (plaintext): text="actual text", from.is_bot=true
- Call signal: text="/call_Offer", call_signal={type,payload}
- File: document={file_name,file_size}
Echo bot (Python):
import requests, time
TOKEN = "your_token"
API = f"http://srv:7700/v1/bot/{TOKEN}"
while True:
for u in requests.post(f"{API}/getUpdates",json={"timeout":50}).json().get("result",[]):
m = u["message"]
if m.get("text"): requests.post(f"{API}/sendMessage",json={"chat_id":m["chat"]["id"],"text":"Echo: "+m["text"]})
time.sleep(1)
Voice Calls
Architecture
Call signaling flows through the featherChat WebSocket (offer/answer/hangup/reject/ringing/busy).
Audio flows through a separate WZP relay infrastructure:
Browser A <--WS--> wzp-web <--QUIC--> wzp-relay <--QUIC--> wzp-web <--WS--> Browser B
| |
featherChat server (/v1/auth/validate)
Key files
- Call signaling:
warzone-server/src/routes/ws.rs (WireMessage::CallSignal handling)
- Call state:
warzone-server/src/state.rs (CallState, active_calls)
- Relay config:
warzone-server/src/routes/wzp.rs (token issuance)
- Web audio:
warzone-server/src/routes/web.rs (startAudio/stopAudio functions)
- TUI calls:
warzone-client/src/tui/commands.rs (/call, /accept, /reject, /hangup)
- Protocol:
warzone-protocol/src/message.rs (CallSignal, CallSignalType)
Environment
WZP_RELAY_ADDR -- tells featherChat server where wzp-web bridge is (e.g., 127.0.0.1:8080)
- Without this,
/v1/wzp/relay-config returns default 127.0.0.1:4433
Commands
cmd
action
example
/call
start voice call with current peer
/call
/call
start voice call with specific peer
/call @alice
/accept
accept incoming call
/accept
/reject
reject incoming call
/reject
/hangup
end current call
/hangup
Relay Config Flow
- Client calls
GET /v1/wzp/relay-config with bearer token
- Server validates auth, issues a short-lived WZP token
- Response:
{"relay_addr":"host:port","token":"..."}
- Client opens WebSocket to
ws://relay_addr with the WZP token
- Audio frames flow over the WebSocket via the wzp-web bridge
Ring Tones
Ring tones play automatically using the Web Audio API (oscillator-based, no audio files):
- Outgoing call: caller hears a ringback tone (repeating double beep) while waiting for answer
- Incoming call: callee hears a ringing tone (classic ring pattern) until they accept/reject
- Both tones stop immediately on answer, reject, or hangup
- TUI clients receive a terminal bell on incoming call (no audio playback)
Group Calls
Group voice calls use the same WZP relay infrastructure but with room-based routing:
Members A,B,C <--WS--> wzp-web <--QUIC--> wzp-relay (room: group:<group_name>)
/gcall signals all group members via the group signal endpoint (POST /v1/groups/:name/signal)
- Room name format:
group:<group_name> (e.g., group:ops)
- Any member can
/gjoin an active group call
/gleave-call leaves the audio room but stays in the text group
/gmute toggles local mic mute (no server-side mixing)
- Group calls are transport-encrypted only; MLS (RFC 9420) E2E planned
Admin Commands
cmd
action
example
/admin-calls
show all active calls on the server
/admin-calls
/admin-help
list available admin commands
/admin-help
Admin commands require server-side admin privilege (configured per-fingerprint).
Server API (other endpoints)
- POST /v1/register -- upload prekey bundle
- GET /v1/keys/:fp -- fetch prekeys for peer
- POST /v1/send -- send encrypted msg
- GET /v1/receive/:fp -- poll msgs (WS preferred)
- WS /v1/ws?fp=&token= -- real-time connection
- GET /v1/presence/:fp -- check online status
- GET/POST /v1/friends -- encrypted friend list
- GET /v1/devices -- list sessions
- POST /v1/devices/:id/kick -- kick device
- Alias routes under /v1/alias/*
- Group routes under /v1/groups/*